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
I highlighted the note, which makes it explicit that the transformed template for
g<auto>
is invalid, sinceA
requires anint
argument, but receives a value of synthesized type†. Consequently, the deduction from theg<int>
template to theg<auto>
template works but not vice versa, sog<int>
is deemed more specialized. I.e. I believe Clang to be in the wrong ong
.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 replacingauto
byint
.† 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 anauto
parameter, and if we adjust the code accordingly, the partial ordering still works the same on GCC.