你被争论的衰败所困扰。
论据衰减意味着那int arr[N]
是花哨的谈话int* arr
。N
完全无视。
最重要的是,arrfill<N-1>
调用模板函数,其第一个参数是 size_t (或兼容)。YourT arr[0]
是一个重载,它的第一个模板参数是一个类型。所以无法选择。
要解决参数衰减,您应该通过引用获取数组。
template<typename T>
bool arrfill(T (&arr)[1], T v){arr[0]=v;}
template<size_t N, typename T>
void arrfill(T (&arr)[N], T v){
arr[0] = v;
arrfill(*reinterpret_cast<T(*)[N-1]>(arr+1), v);
}
可悲的是,这是未定义的行为;我将数组的一部分转换为不是类型的数组。这恰好是未定义的行为,我曾经使用过的每个 C++ 编译器都会消耗并执行“正确的事情”,但它仍然是未定义的行为。我们应该避免这种情况,除非我们有充分的理由不这样做;虽然干净清晰,但干净的代码(在我看来)不是做 UB 的好理由。10 年后,当编译器更新时,UB 可能会回来咬我们,我不想在每次编译器更新时都维护这段代码并确保它仍然有效。
所以真的,使用包装和折叠。
template<size_t N, typename T,std::size_t...Is>
void arrfill(T (&arr)[N], T v,std::index_sequence<Is...>){
((void)(arr[Is]=v),...);
}
template<size_t N, typename T>
void arrfill(T (&arr)[N], T v){
arrfill(arr, v, std::make_index_sequence<N>{});
}
或者只是使用std::fill_n
.
template<size_t N, typename T>
void arrfill(T (&arr)[N], T v){
std::fill_n( std::begin(arr), N, v );
}
如果你真的,真的必须使用递归
template<size_t N, typename T>
void arrfill(T* arr, T v){
if constexpr(N==0) {
return;
} else {
arr[0] = v;
arrfill<N-1>(arr+1, v);
}
}
可以。在c++11中,我们不能使用 if constexpr。所以我们做点别的。
template<typename T>
void arrfill(std::integral_constant<std::size_t, 0>, T* arr, T const& v){
}
template<size_t N, typename T>
void arrfill(std::integral_constant<std::size_t, N>, T* arr, T const& v){
arr[0] = v;
arrfill(std::integral_constant<std::size_t, N-1>{}, arr+1, v);
}
template<size_t N, typename T>
void arrfill(T(&arr)[N], T const& v){
arrFill(std::integral_constant<std::size_t, N>{}, arr, v);
}
这让我们可以使用重载选择 0 情况。我们也自动推断N
。