C++ 变量函数模板中未推导上下文

C++ 变量函数模板中未推导上下文,c++,c++11,variadic-templates,template-argument-deduction,C++,C++11,Variadic Templates,Template Argument Deduction,正如我所知,下面的代码应该是“非推断上下文”(或者不是?) 模板 空f(X…args,Y) { } int main() { f(12); f(1,2,3,4); } 但是g++4.9为main中的f的两个实例化编译它。。。 有人能解释一下吗?这条规则只适用于类模板,而不适用于函数,因为可以为函数推导模板。如果在类模板上尝试此操作,您将看到错误: template <class... X, class Y> class C { // This won't compile. };

正如我所知,下面的代码应该是“非推断上下文”(或者不是?)

模板
空f(X…args,Y)
{
}
int main()
{
f(12);
f(1,2,3,4);
}
但是g++4.9为
main
中的
f
的两个实例化编译它。。。
有人能解释一下吗?

这条规则只适用于类模板,而不适用于函数,因为可以为函数推导模板。如果在类模板上尝试此操作,您将看到错误:

template <class... X, class Y>
class C {  // This won't compile.
};
模板
类C{//这不会编译。
};
有关更多信息,请参阅中的第7页:

如果类模板的模板参数是模板参数 pack,它必须是最后一个模板参数。注意:这不是一个问题 要求这些不是功能模板的要求,因为 可以推断模板参数(14.8.2)

第一个调用
f(12)
格式不正确。根据[temp.Decrete.type]/p5.7,未出现在参数声明末尾的参数包是非推断上下文:

非推断上下文为:

-[……]

-不出现在参数声明列表末尾的函数参数包

在[temp.Decrete.call]/p1中进一步说明:

对于出现在参数声明列表末尾的函数参数包,将调用的每个剩余参数的类型
a
与函数参数包的声明器id的类型
p
进行比较。每次比较都会为函数参数包展开的模板参数包中的后续位置推导模板参数当函数参数包出现在非推断上下文(14.8.2.5)中时,该参数包的类型永远不会推断。

[示例:

模板无效f(类型和…);
模板空隙g(T1,类型…);
模板无效g1(类型…,T1);
无效h(整数x、浮点和y){
常数int z=x;
f(x,y,z);//类型被推导为int,float,const int
g(x,y,z);//T1推导为int;类型推导为float,int
g1(x,y,z);//错误:未推导类型
g1(x,y,z);//好的,不进行扣减
}
-[结束示例]

因此,参数pack
X..
不能由函数的参数推导,模板参数推导失败。GCC接受第一个调用,而不是因为没有推断
12
而拒绝模板,因此它似乎是一个bug

然而,第二个调用,
f(1,2,3,4)
,根据[temp.decrete]/p6是格式良好的。显式指定的模板参数将立即替换函数模板的模板参数。这意味着
X={int,int,int}
。然后,模板参数推断继续进行,从最右边的参数推断出
Y
,即
int

在模板参数推导过程中的某些点上,需要采用使用模板参数的函数类型,并用相应的模板替换这些模板参数 争论当任何显式指定的模板 参数被替换到函数类型中,并再次替换到模板参数推断的末尾 替换从默认参数推导或获得的任何模板参数。

请注意([临时扣减]/p2):

除非至少有一个参数是模板参数包,否则参数的数量不得超过参数的数量,并且每个非包参数都应有一个参数

Clang不接受最后一个函数调用,但GCC接受。我相信这是一个叮当作响的错误



请注意,在参数包出现之后,对于默认参数的使用有一个开放的定义。在这种情况下,Clang的行为也存在争议。

调用是否被优化了?
template <class... X, class Y>
class C {  // This won't compile.
};