This is CWG1395, for which a defect resolution was recently voted in to the draft C++17 standard. The following was added to [temp.deduct.partial]:
...[if] 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
.
The standard doesn't explicitly define what it means by "trailing parameter pack", but judging by the existing contexts in which this term is used, it refers to a template parameter pack that appears as the rightmost parameter in a template parameter list:
template<class T, class... U> struct X;
// ^^^^^^^^^^
Or, a function parameter pack that appears as the rightmost parameter in a function parameter list:
template<class T, class... U> void y(T, U...);
// ^^^^
The current draft still contains this outdated example in [temp.deduct.type]:
template<class T, class... U> void f(T, U...);
template<class T> void f(T);
f(&i); // error: ambiguous
This standard defect report has been around for a few years, and both GCC and Clang have implemented resolutions of it. They both agree that the example above is a valid call of the second overload of f
.
Where GCC and Clang disagree is on the scope of the defect resolution. This is understandable, as it was only recently updated to include proposed standard wording. In your example, the pack is not expanded into the function parameter list, but into the template argument list of a function parameter type:
template<class T, class... U> void g(tuple<T, U...>);
template<class T> void g(tuple<T>);
g(tuple<int>{});
GCC treats this as a valid call of the second overload of g
; Clang treats it as ambiguous. The correctness of Clang may depend on whether "trailing parameter pack" is intended to include trailing template parameter packs, or only trailing function parameter packs.
Note that both compilers agree that C<int>
refers to the second partial specialization of the class template C
in the following example:
template<class...> struct C;
template<class T, class... U> struct C<T, U...> {};
template<class T> struct C<T> {};
This seems like an inconsistency in Clang, because the standard rules for partial ordering of class template specializations is defined in terms of partial ordering of function templates. See CWG1432.