C++ 当参数为函数参数包时,在偏序期间推导模板参数
N4527 14.8.2.4[温度扣除部分] 3用于确定排序的类型取决于进行部分排序的上下文: (3.1)-在函数调用的上下文中,使用的类型是那些函数调用具有参数的函数参数类型 (3.2)-在调用转换函数的上下文中,使用转换函数模板的返回类型 (3.3)-在其他上下文(14.5.6.2)中,使用功能模板的功能类型 4以上从参数模板中指定的每种类型以及从参数中指定的相应类型 模板用作C++ 当参数为函数参数包时,在偏序期间推导模板参数,c++,templates,c++11,variadic-templates,overload-resolution,C++,Templates,C++11,Variadic Templates,Overload Resolution,N4527 14.8.2.4[温度扣除部分] 3用于确定排序的类型取决于进行部分排序的上下文: (3.1)-在函数调用的上下文中,使用的类型是那些函数调用具有参数的函数参数类型 (3.2)-在调用转换函数的上下文中,使用转换函数模板的返回类型 (3.3)-在其他上下文(14.5.6.2)中,使用功能模板的功能类型 4以上从参数模板中指定的每种类型以及从参数中指定的相应类型 模板用作P和A的类型 8如果A是从函数参数包转换而来,并且p不是参数包,则类型推断失败。 否则,使用结果类型P和A,然后按照
P
和A
的类型
8如果A
是从函数参数包转换而来,并且p
不是参数包,则类型推断失败。
否则,使用结果类型P
和A
,然后按照14.8.2.5中的说明进行扣除。如果P
是函数参数包,参数模板的每个剩余参数类型的类型为
与函数参数包的声明器id的类型P
进行比较。每次比较都会得出结论
函数展开的模板参数包中后续位置的模板参数
参数包。如果对给定类型的推断成功,则将考虑参数模板中的类型
至少与参数模板中的类型一样专用。
[示例:
为什么f(1,2,3);
calls#2
您的问题中有很多问题(请每个问题一个问题!),因此我将坚持这一个问题。首先,我们执行模板推导。#3失败,但#1和#2成功:
template<class... Args>
void f(Args... args); // #1, with Args = {int, int, int}
template<class T1, class... Args>
void f(T1 a1, Args... args); // #2, with T1 = int, Args = {int, int}
步骤2:按照[temp.Decrete.partial]中所述执行推断。我们所处的上下文是函数调用,因此我们使用函数调用具有参数的类型
首先,我们尝试从#1中推断#2。也就是说,我们尝试将(T1,Args…
)与(Pack1…
)匹配。第一部分是p=T1,A=Pack1…
。我们有:
如果A是从函数参数包转换而来,而p不是参数包,则类型推断失败
因此,从#1推断#2失败,因此参数Args…
至少不像T1,Args…
那样专业化
接下来,我们尝试从#2中推断#1。也就是说,我们尝试将(Args…
与(U2,Pack2…
)进行匹配。这样成功了,T1,Args…
至少与Args…
一样专业化
由于#2至少和#1一样专业,而#1至少没有#2那么专业,我们可以说#2更专业:
函数模板F
对于用于
确定顺序时,来自F
的类型至少与来自G
的类型一样专业化F
的类型更专业化
如果F
至少与G
一样专业,并且G
至少不如F
那么专业,那么G
就比G
更专业
更专业的模板是首选的,因此我们称之为#2
template <class T> void f(T);
int a = 1;
f(a);//P = T, A = int
template<class... Args>
void f(Args... args); // #1, with Args = {int, int, int}
template<class T1, class... Args>
void f(T1 a1, Args... args); // #2, with T1 = int, Args = {int, int}
void f(Pack1... args); // #1
void f(U2 a1, Pack2... args); // #2