基本上,我想要的是像multi_types std::initializer_list这样的东西
template<typename ...As>
struct Foo {
Foo(As...){}
};
template<typename ...As>
void f(Foo<As...>) {}
int main() {
f(Foo{5, 3.f}); // 1) compile
f({}); // 2) compile
f({5, 3}); // 3) error
f({5, 3.8}); // 4) error
return 0;
}我理解为什么第一个示例会编译。然而,我不明白为什么第二个编译,而其他的不编译。对我来说,第二个也不应该编译,如果第三和第四不编译。有没有办法进行第三次和第四次编译?
发布于 2019-03-17 18:33:17
然而,我不明白为什么第二个编译,而其他的不编译。
示例3和4无法编译,因为推导出的模板参数与您预期的不同。
当您将调用(f({5, 3}))写入函数模板template<typename ...As> void f(Foo<As...>)时,编译器需要推断任何缺少的模板参数(...As)。首先通过比较函数参数({5, 3})和函数参数(Foo<As...>),推导出这些缺少的模板参数。如果函数参数是初始化程序列表({5, 3}) 1,则函数参数(Foo<As...>)跳过模板参数演绎:
N4659 temp.deduct.call 17.8.2.1(1):初始化程序列表参数导致参数被视为非推导的上下文(17.8.2.5)。N4659 temp.deduct.type 17.8.2.5(5.6):非推导的上下文包括一个函数参数,其相关的参数是一个初始化器列表(11.6.4) .
由于尾随模板参数pack (As...)不是由任何函数参数推导出来的,因此它被推断为空:
N4659 temp.arg.explicit 17.8.1(3):未导出的尾随模板参数包(17.5.3)将被推导为模板参数的空序列。
对于void f(Foo<>).,编译器推断模板参数是<> (空),因此调用的专门化是。重要:不管初始化程序列表中的是什么,都会选择此专门化。这就解释了编译器提供的诊断:
嘎吱声: 错误:对“f”的调用没有匹配函数 注意:带有As = <>的候选函数不可行:不能将初始化程序列表参数转换为“Foo<>” GCC: 错误:无法将“{5,3}”从“”转换为“Foo<>” MSVC: 错误C2664:'void f<>(Foo<>)':无法将参数1从“初始化程序列表”转换为“Foo<>” 注意:任何构造函数都不能接受源类型,或者构造函数重载解析不明确。
在函数调用中,函数参数使用函数参数的复制初始化来初始化.以下语句使用与示例初始化f参数相同的规则初始化变量
Foo<> x = {}; // Example 2
Foo<> x = {5, 3}; // Example 3
Foo<> x = {5, 3.8}; // Example 4简而言之,如果函数参数既不是std::initializer_list<T>也不是T[n]
发布于 2019-03-17 19:00:33
有没有办法进行第三次和第四次编译?
我认为没有办法更改f或Foo来编译第四个示例。
要编译第三个示例,可以添加f的重载,该重载包含一个数组:
#include <cstddef>
#include <utility>
#define EXPLICIT_TEMPLATE_ARGUMENTS 1
//#define EXPLICIT_TEMPLATE_ARGUMENTS 0
#if EXPLICIT_TEMPLATE_ARGUMENTS
template<class T, std::size_t>
struct identity {
using type = T;
};
#endif
template<class ...As>
struct Foo {
Foo(As...);
};
template<class ...As>
void f(Foo<As...>);
template<class A, std::size_t N, std::size_t ...Indexes>
void f_helper(A const (&as)[N], std::index_sequence<Indexes...>) {
static_assert(N == sizeof...(Indexes));
#if EXPLICIT_TEMPLATE_ARGUMENTS
// Example pack expansions:
// return f<>(Foo<>{});
// return f<A>(Foo<A>{as[0]});
// return f<A, A>(Foo<A, A>{as[0], as[1]});
return f<typename identity<A, Indexes>::type...>(Foo<typename identity<A, Indexes>::type...>{as[Indexes]...});
#else
// Example pack expansions:
// return f(Foo{});
// return f(Foo{as[0]});
// return f(Foo{as[0], as[1]});
return f(Foo{as[Indexes]...});
#endif
}
// Call as: f({x, y, z})
template<class A, std::size_t N>
void f(A const (&as)[N]) {
return f_helper<A, N>(as, std::make_index_sequence<N>());
}
int main() {
f(Foo{5, 3.f}); // 1) compile
f({}); // 2) compile
f({5, 3}); // 3) compile (was: error)
f({5, 3.8}); // 4) error
return 0;
}https://stackoverflow.com/questions/54824308
复制相似问题