C++ 当参数为函数参数包时,在偏序期间推导模板参数

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,然后按照

N4527 14.8.2.4[温度扣除部分]

3用于确定排序的类型取决于进行部分排序的上下文:

(3.1)-在函数调用的上下文中,使用的类型是那些函数调用具有参数的函数参数类型

(3.2)-在调用转换函数的上下文中,使用转换函数模板的返回类型

(3.3)-在其他上下文(14.5.6.2)中,使用功能模板的功能类型

4以上从参数模板中指定的每种类型以及从参数中指定的相应类型 模板用作
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