函数重载:空参数列表与参数包
Function overloading: empty parameter list vs parameter pack
template <typename T>
void call(T) { //#1
std::cout << "1" << std::endl;
}
template <typename T, typename...Args>
void call(T, Args...) { //#2
std::cout << "2" << std::endl;
}
当我这样调用函数时
call(10);
GCC、Clang 和 MSVC 都使用 #1。
但是,标准中的部分排序规则说:
If the parameter-declaration corresponding to Pi is a function parameter pack, then the type of its declarator-id is compared with each remaining parameter type in the parameter-type-list of A. Each comparison deduces template arguments for subsequent positions in the template parameter packs expanded by the function parameter pack. During partial ordering, if Ai was originally a function parameter pack:
(10.1) if P does not contain a function parameter type corresponding to Ai then Ai is ignored;
(10.2) otherwise, if Pi is not a function parameter pack, template argument deduction fails.
当我们从#2推导出#1时,T, Args...
为A,T
为P,P不包含对应于Args...
的模板参数。 Args...
被忽略,所以#1可以成功地从#2推导出来。
然后从#1推导#2,T
为A,T, Args...
为P,也成功得到T = T, Args... = {}
。
因此,根据偏序规则,在调用call(10)
时,编译器应该会给出模棱两可的错误,但实际上所有编译器都调用了#1,这是为什么?
编译器是正确的。 #1
比 #2
更专业。
部分排序模板参数包的规则在[temp.deduct.partial]/8中指定:
Using the resulting types P
and A
, the deduction is then done as
described in [temp.deduct.type]. If P
is a function parameter pack,
the type A
of each remaining parameter type of the argument template
is compared with the type P
of the declarator-id of the function
parameter pack. Each comparison deduces template arguments for
subsequent positions in the template parameter packs expanded by the
function parameter pack. Similarly, if A
was transformed from a
function parameter pack, it is compared with each remaining parameter
type of the parameter template. If deduction succeeds for a given
type, the type from the argument template is considered to be at least
as specialized as the type from the parameter template.
当参数模板为#1
且参数模板为#2
时,declarator-id Args
(这是一个类型) 来自 #2
与 #1
中的每个剩余参数(有 none)进行比较。因此,#2
至少与 #1
.
一样专业
当参数模板为#2
且参数模板为#1
时,declarator-id Args
(这是一个类型) 来自 #2
与 #1
中的每个剩余参数(有 none)进行比较。因此,#1
至少与 #2
.
一样专业
好像很暧昧吧?现在我们有了决胜局,[temp.deduct.partial]/11:
If, after considering the above, function template F
is at least as
specialized as function template G
and vice-versa, and if G
has a
trailing parameter pack for which F
does not have a corresponding
parameter, and if F
does not have a trailing parameter pack, then
F
is more specialized than G
.
显然,#1
比 #2
更专业。
template <typename T>
void call(T) { //#1
std::cout << "1" << std::endl;
}
template <typename T, typename...Args>
void call(T, Args...) { //#2
std::cout << "2" << std::endl;
}
当我这样调用函数时
call(10);
GCC、Clang 和 MSVC 都使用 #1。
但是,标准中的部分排序规则说:
If the parameter-declaration corresponding to Pi is a function parameter pack, then the type of its declarator-id is compared with each remaining parameter type in the parameter-type-list of A. Each comparison deduces template arguments for subsequent positions in the template parameter packs expanded by the function parameter pack. During partial ordering, if Ai was originally a function parameter pack:
(10.1) if P does not contain a function parameter type corresponding to Ai then Ai is ignored;
(10.2) otherwise, if Pi is not a function parameter pack, template argument deduction fails.
当我们从#2推导出#1时,T, Args...
为A,T
为P,P不包含对应于Args...
的模板参数。 Args...
被忽略,所以#1可以成功地从#2推导出来。
然后从#1推导#2,T
为A,T, Args...
为P,也成功得到T = T, Args... = {}
。
因此,根据偏序规则,在调用call(10)
时,编译器应该会给出模棱两可的错误,但实际上所有编译器都调用了#1,这是为什么?
编译器是正确的。 #1
比 #2
更专业。
部分排序模板参数包的规则在[temp.deduct.partial]/8中指定:
Using the resulting types
P
andA
, the deduction is then done as described in [temp.deduct.type]. IfP
is a function parameter pack, the typeA
of each remaining parameter type of the argument template is compared with the typeP
of the declarator-id of the function parameter pack. Each comparison deduces template arguments for subsequent positions in the template parameter packs expanded by the function parameter pack. Similarly, ifA
was transformed from a function parameter pack, it is compared with each remaining parameter type of the parameter template. If deduction succeeds for a given type, the type from the argument template is considered to be at least as specialized as the type from the parameter template.
当参数模板为#1
且参数模板为#2
时,declarator-id Args
(这是一个类型) 来自 #2
与 #1
中的每个剩余参数(有 none)进行比较。因此,#2
至少与 #1
.
当参数模板为#2
且参数模板为#1
时,declarator-id Args
(这是一个类型) 来自 #2
与 #1
中的每个剩余参数(有 none)进行比较。因此,#1
至少与 #2
.
好像很暧昧吧?现在我们有了决胜局,[temp.deduct.partial]/11:
If, after considering the above, function template
F
is at least as specialized as function templateG
and vice-versa, and ifG
has a trailing parameter pack for whichF
does not have a corresponding parameter, and ifF
does not have a trailing parameter pack, thenF
is more specialized thanG
.
显然,#1
比 #2
更专业。