What are the rules for the selection of overloaded function templates in case of non-type template parameters, if one of the parameters is a placeholder type. I am confused with the current behavior of the compilers, consider the next example:
template<int N> struct A{};
template<auto... N> void f(A<N...>);
template<int N> void f(A<N>) {}
template<auto N> void g(A<N>);
template<int N> void g(A<N>) {}
int main() {
f( A<1>{} ); // ok in GCC and Clang, error in MSVC
g( A<1>{} ); // ok in GCC, error in Clang and MSVC
}
Here MSVC fails to select between both sets of overloads. On the other hand, GCC always selects the function template with the more concrete type <int>
. And Clang is somewhat in the middle, preferring <int>
over the parameter pack <auto...>
, but it sees ambiguity during selection between <int>
and <auto>
overloads. Online demo: https://gcc.godbolt.org/z/4EK99Gjhx
Which one of the behaviors is correct or the standard is not clear about it?
This is likely underspecified, but we can explain the general behavior of implementations with partial ordering rules. In [temp.func.order], it is said that
To produce the transformed template, for each type, non-type, or template template parameter (including template parameter packs thereof) synthesize a unique type, value, or class template respectively and substitute it for each occurrence of that parameter in the function type of the template.
[Note 1: The type replacing the placeholder in the type of the value synthesized for a non-type template parameter is also a unique synthesized type. — end note]
I highlighted the note, which makes it explicit that the transformed template for g<auto>
is invalid, since A
requires an int
argument, but receives a value of synthesized type†.
Consequently, the deduction from the g<int>
template to the g<auto>
template works but not vice versa, so g<int>
is deemed more specialized. I.e. I believe Clang to be in the wrong on g
.
For f
we have the simpler rule from [temp.deduct.type]/9.2 that governs partial ordering of specializations, and would make the variadic overload more specialized even when replacing auto
by int
.
† I can't find anything in the wording about invalid transformed templates, only a related clause from P0522 which clarifies that an invalid rewritten form causes the rewritten template not to be at least as specialized (the intuitive behavior for partial ordering, too). But even if we assumed that A
could accept an arbitrarily typed value, i.e. had itself an auto
parameter, and if we adjust the code accordingly, the partial ordering still works the same on GCC.