据我所知,以下代码应该是“不推断上下文”(或不是?)
template <class... X, class Y>
void f(X... args, Y y)
{
}
int main()
{
f(12);
f<int, int, int>(1, 2, 3, 4);
}
f
但是 g++ 4.9 为in的两个实例编译它main
...有人能解释一下吗?
据我所知,以下代码应该是“不推断上下文”(或不是?)
template <class... X, class Y>
void f(X... args, Y y)
{
}
int main()
{
f(12);
f<int, int, int>(1, 2, 3, 4);
}
f
但是 g++ 4.9 为in的两个实例编译它main
...有人能解释一下吗?
第一个电话f(12)
格式不正确。没有出现在参数声明末尾的参数包是根据 [temp.deduct.type]/p5.7 的非推导上下文:
未推断的上下文是:
— [..]
—不出现在参数声明列表末尾的函数参数包
进一步在 [temp.deduct.call]/p1 中:
对于出现在parameter-declaration-list
A
末尾的函数参数包,将调用的每个剩余参数的类型与函数参数包P
的declarator-id的类型进行比较。每个比较推导出模板参数包中由函数参数包扩展的后续位置的模板参数。当函数参数包出现在非推导上下文 (14.8.2.5) 中时,永远不会推导该参数包的类型。[ 例子:
template<class ... Types> void f(Types& ...); template<class T1, class ... Types> void g(T1, Types ...); template<class T1, class ... Types> void g1(Types ..., T1); void h(int x, float& y) { const int z = x; f(x, y, z); // Types is deduced to int, float, const int g(x, y, z); // T1 is deduced to int; Types is deduced to float, int g1(x, y, z); // error: Types is not deduced g1<int, int, int>(x, y, z); // OK, no deduction occurs }
—结束示例]
因此参数包X...
不能由函数的参数推导,模板参数推导失败。GCC 接受第一次调用,而不是拒绝不推导的模板,12
因此它似乎是一个错误。
f<int, int, int>(1, 2, 3, 4)
然而,根据 [temp.deduct]/p6,第二个调用是格式良好的。显式指定的模板参数会立即替换函数模板的模板参数。这意味着X = {int, int, int}
。然后模板参数推导继续Y
从最右边的参数推导为int
:
在模板参数推导过程中的某些点,有必要采用使用模板参数的函数类型并将这些模板参数替换为相应的模板参数。当任何显式指定的模板参数被替换为函数类型时,这在模板参数推导的开头完成,并且在模板参数推导结束时,当任何从默认参数推导或获得的模板参数被替换时再次完成。
请注意([temp.deduct]/p2):
除非至少一个形参是模板形参 pack ,否则实参的个数不得多于形参,并且每个非打包形参都应有一个实参。
Clang 不接受最后一个函数调用,但 GCC 可以。我相信这是一个 Clang 错误。
请注意,在出现参数包后,有一个与使用默认参数有关的开放式CWG 问题 1609 。还有LLVM Bug 21774对 Clang 在这种情况下的行为提出异议。
该规则仅适用于类模板,不适用于函数,因为可以为函数推导出模板。如果你在类模板上尝试,你会看到错误:
template <class... X, class Y>
class C { // This won't compile.
};
有关详细信息,请参阅http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2242.pdf中的第 7 页:
如果类模板的模板参数是模板参数包,它必须是最后一个模板参数。注意:这不是要求这些不是函数模板的要求,因为可能会推导出模板参数 (14.8.2)