以下代码编译并运行正常。
void foo() {
}
template <typename T, typename... Args>
void foo(T x, Args... args) {
cout << x << endl;
foo(args...);
}
// inside main()
foo(1,1,1);
此其他代码无法编译:
void foo() {
}
template <typename... Args, typename T>
void foo(Args... args, T x) {
foo(args...);
cout << x << endl;
}
// inside main()
foo(1,1,1);
编译器说调用foo(1,1,1)
没有匹配函数,并说foo(Args... args, T x)
是候选函数,但模板参数推导/替换失败,因为候选者需要1个参数,但提供了3个参数
这种情况是否存在任何编译器无法处理的歧义?这个编译错误对我来说似乎不合逻辑。也许这有点与C ++标准无关?
答案 0 :(得分:6)
来自Clang's error message的有趣部分是:
main.cpp:11:6: note: candidate template ignored: couldn't infer template argument 'T'
void foo(Args... args, T x) {
^
问题是参数包Args...
出现之前到T
。
Args...
&#34;贪婪&#34;所以没有任何参数可供编译器推导T
,因此它失败了。
引用标准(强调我的):
<强> [temp.param] / 11 强>
不得遵循功能模板的模板参数包 另一个模板参数除非该模板参数可以 从函数模板的参数类型列表中推导出或具有 默认参数。 [实施例:
... // U can be neither deduced from the parameter-type-list nor specified template<class... T, class... U> void f() { } // error template<class... T, class U> void g() { } // error
- 结束示例]
答案 1 :(得分:6)
(此答案基于@JohannesSchaub-litb's comments)
根据标准,如果模板参数包用于不在参数列表末尾的函数参数包中,则不能推导出模板参数包。
§14.8.2.1/1 Deducing template arguments from a function call [temp.deduct.call]:
当函数参数包出现在非推导的上下文中时 ([temp.deduct.type]),该参数包的类型永远不会 推导。 [例如:
template<class T1, class ... Types> void g1(Types ..., T1); void h(int x, float& y) { const int z = x; g1(x, y, z); // error: Types is not deduced g1<int, int, int>(x, y, z); // OK, no deduction occurs }
- 结束示例]
关于未推断的背景,§14.8.2.5/5 Deducing template arguments from a type [temp.deduct.type]:
不在参数声明列表末尾出现的函数参数包。
因此foo(1,1,1);
失败的直接原因是不推导出模板参数Args
,这对于使函数调用有效是必要的。
为了解释错误消息,未推导出的模板参数包将被推导为模板参数 [1] 的空序列,这意味着它将被省略。然后foo(1,1,1);
失败,因为参数的数量不匹配,这就是编译器所抱怨的。
正如所示的标准示例一样,您可以明确指定模板参数以避免类型推导,即使它不符合代码的原始意图。如:
template <typename T, typename... Args>
void foo(Args... args, T x) {
}
int main() {
// inside main()
foo<int, int, int>(1, 1, 1);
}
Here还有一些额外的信息。
[1]我在标准中找不到关于此的直接表达。最接近的是this,“否则推导出的尾随模板参数包([temp.variadic])将被推导为空的模板参数序列。”