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;
}
When I call the function like this
call(10);
GCC, Clang, and MSVC all use #1.
However, the partial ordering rule in the standard says:
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.
When we deduce #1 from #2, with T, Args...
as A, T
as P, P does not contain a template argument corresponding to Args...
. Args...
is ignored, so #1 can be deduced from #2 successfully.
Then the deducing #2 from #1, with T
as A and T, Args...
as P, also successfully results in T = T, Args... = {}
.
Therefore, according to the partial ordering rules, when call call(10)
, the compiler should be giving the ambiguous error, but in fact all compiler called #1, why is this?
The compilers are correct. #1
is more specialized than #2
.
The rule for partial ordering template parameter packs is specified in [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.
When the parameter template is #1
and the argument template is #2
, the declarator-id Args
(which is a type) from #2
is compared with each of the remaining parameters in #1
(there's none). Therefore, #2
is at least as specialized as #1
.
When the parameter template is #2
and the argument template is #1
, the declarator-id Args
(which is a type) from #2
is compared with each of the remaining parameters in #1
(there's none). Therefore, #1
is at least as specialized as #2
.
Seems ambiguous, right? Now we have the tie breaker, [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
.
Apparently, #1
is more specialized than #2
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With