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, sinceArequires anintargument, 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
fwe 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 replacingautobyint.† 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
Acould accept an arbitrarily typed value, i.e. had itself anautoparameter, and if we adjust the code accordingly, the partial ordering still works the same on GCC.