I think the code is well-formed, and MSVC is incorrect.

The strange thing in this example is that since class template C has one non-pack parameter, the second function template involving C<T...> can only have valid specializations with sizeof...(T)==1. If I change C to be a variadic class template, "template<typename... T> struct C {};", I notice MSVC agrees with the other compilers that the code is well-formed.

But I don't see anything which says that this situation using a pack expansion as the argument for a non-pack parameter is ill-formed, or makes any difference to the function template partial ordering procedure. The fact remains that the transformed type from the second function template has A_1 which was originally a pack expansion and P_1 from the first function template is not a pack expansion, so deduction of the first f from the transformed second f fails ([temp.deduct.type]/(9.2), just before the Example quoted in the OP.). Deduction of the second f from the transformed first f succeeds. So the first f is more specialized than the second f and the first f should be selected.

I don't see a need for clarification or more examples in the Standard.

-- Andrew Schepler


On Tue, Jun 21, 2022 at 2:50 PM Anoop Rana via Std-Discussion <std-discussion@lists.isocpp.org> wrote:
Is the example well formed? That is should the call f(C<int>{}) succeed?

On Sun, 19 Jun 2022, 15:35 Anoop Rana, <ranaanoop986@gmail.com> wrote:
I was working with parameter packs when I noticed that one such case(given below) doesn't compile in msvc but compiles fine in gcc and clang. Here is the link for the verification of the same: link to demo

The code is as follows:

template<typename T> struct C{};

template<typename T> void f(C<T>)
{

}
template<typename... T> void f(C<T...>)
{

}
int main()
{
    f(C<int>{}); //Should this call succeed? 
}
I want to know if the above example is well-formed according to the standard. I mean should the call f(C<int>{}); succeed by choosing the first overload version `void f(C<T>)`  over the second version.

For possible explanation i looked at examples given in: temp.deduct.type#9.2:
[Example
template<class T1, class... Z> class S;                                 // #1
template<class T1, class... Z> class S<T1, const Z&...> { };            // #2
template<class T1, class T2>   class S<T1, const T2&> { };              // #3
S<int, const int&> s;           // both #2 and #3 match; #3 is more specialized
End Example]

My current understanding/intuition is that the example that I gave here should be valid as well and the first overload should be chosen over the second. 
If so, should this or a similar example be added in temp.deduct.type to make this more clear? 
Basically I want to know if the intention for the same(i.e., for allowing the example that i gave) was always there but was not clearly conveyed. If not, then is there a clause that clear disallows
the example that i gave which i missed to notice/understand.
--
Std-Discussion mailing list
Std-Discussion@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion