如我所知,以下代码应该是“不推断上下文”(或不是?)
template <class... X, class Y>
void f(X... args, Y y)
{
}
int main()
{
f(12);
f<int, int, int>(1, 2, 3, 4);
}
但g ++ 4.9为f
中main
的两个实例化编译它...
有人可以解释一下吗?
答案 0 :(得分:0)
该规则仅适用于类模板,而不适用于函数,因为可以推导出模板的功能。如果您在课程模板上尝试,则会看到错误:
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页如果类模板的模板参数是模板参数 pack,它必须是最后一个模板参数。注意:这不是 要求这些不是功能模板的要求,因为 可以推导出模板参数(14.8.2)
答案 1 :(得分:0)
第一个电话f(12)
格式不正确。未出现在参数声明末尾的参数包是每个[temp.deduct.type] /p5.7的非推断上下文:
未推断的上下文是:
- [..]
- parameter-declaration-list
结束时未出现的函数参数包
进一步在[temp.deduct.call] / p1:
对于出现在 parameter-declaration-list 末尾的函数参数包,将调用每个剩余参数的类型
A
与类型{{1函数参数包的 declarator-id 。每个比较都推导出函数参数包扩展的模板参数包中后续位置的模板参数。 当函数参数包出现在非推导的上下文(14.8.2.5)中时,永远不会推导出该参数包的类型。[例如:
P
- 结束示例]
因此,函数的参数无法推导出参数包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
}
,模板参数推断失败。 GCC接受第一次调用,而不是拒绝模板而不推断X...
所以它似乎是一个错误。
然而,第二个调用12
根据[temp.deduct] / p6格式良好。显式指定的模板参数会立即替换函数模板的模板参数。这意味着f<int, int, int>(1, 2, 3, 4)
。模板参数推导然后继续X = {int, int, int}
从最右边的参数推导为Y
:
在模板参数推导过程中的某些点,有必要采用一个使用模板参数的函数类型,并用相应的模板替换这些模板参数 参数。 当任何明确指定的模板时,这是在模板参数推断开始时完成的 参数被替换为函数类型,并且在模板参数推断的末尾再次被替换 当从默认参数推断或获得的任何模板参数被替换时。
另请注意([temp.deduct] / p2):
参数必须没有更多参数,除非至少有一个参数是模板参数包,并且每个非包参数都应该有一个参数。
Clang不接受最后一次函数调用,但是GCC会这样做。我相信这是一个Clang bug。
请注意,在发生参数包后,有一个与使用default-arguments有关的开放CWG issue 1609。还有LLVM Bug 21774对Clang在这种情况下的行为提出质疑。