The first call to f(12) poorly formed. The package of parameters that does not appear at the end of the parameter declaration is an untrackable context for [temp.deduct.type] /p5.7:
Impossible contexts:
- [..]
- A package of function parameters that does not occur at the end of the list of declaration parameters
Further in [temp.deduct.call] / p1:
For the package of function parameters that occurs at the end of the parameter-declaration-list, type A each remaining call argument is compared with type P the function parameter parameter declaration identifier pack. Each comparison displays the template arguments for subsequent positions in the parameter template packages extended by the function parameter package. When a package of function parameters appears in an undetectable context (14.8.2.5), the type of this parameter package is never displayed.
[Example:
template<class ... Types> void f(Types& ...); template<class T1, class ... Types> void g(T1, Types ...); template<class T1, class ... Types> void g1(Types ..., T1); void h(int x, float& y) { const int z = x; f(x, y, z);
- end of example]
Thus, the package of parameters X... cannot be output by function arguments, and the output of the template argument is not performed. GCC accepts the first call instead of rejecting the pattern so as not to output 12 , so it seems like an error.
The second call f<int, int, int>(1, 2, 3, 4) , however, is well-formed according to [temp.deduct] / p6. The explicitly specified template arguments are immediately replaced by the template parameters of the function template. This means X = {int, int, int} . Then the output of the template argument continues with Y , which is inferred from the rightmost argument as int :
In some cases of the process of subtracting the template argument, it is necessary to take a function type that uses the template parameters and replaces these template parameters with the corresponding template arguments. This is done at the beginning of the output of the template argument, when any explicitly specified template, the arguments are substituted into the type of the function and again at the end of the output of the template argument when any template arguments that were derived or obtained from the default arguments are substituted.
Note that also ([temp.deduct] / p2):
There should not be more arguments than there are parameters , if at least one parameter is a package of template parameters , and there should be an argument for each parameter without a package.
Clang does not accept the last function call, but GCC does. I believe this is a Clang error.
Note that there is an open CWG issue 1609 regarding the use of default arguments after the appearance of a parameter package. There is also LLVM Bug 21774 , which disputes Clan behavior in this context.