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
PandA, the deduction is then done as described in [temp.deduct.type]. IfPis a function parameter pack, the typeAof each remaining parameter type of the argument template is compared with the typePof 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, ifAwas 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
Fis at least as specialized as function templateGand vice-versa, and ifGhas a trailing parameter pack for whichFdoes not have a corresponding parameter, and ifFdoes not have a trailing parameter pack, thenFis 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