So my question is, is the above shown code example well formed.
The code is well-formed as the function template overload with a non-variadic template parameter is more specialized than the overload with a variadic template parameter, by partial ordering rules.
MSVC is incorrect to reject it.
[temp.func.order]/1 through /4 tells us that we need to turn to partial ordering
/1 If a function template is overloaded, the use of a function template
specialization might be ambiguous [...]. Partial ordering of overloaded function template declarations is used in the following contexts to select the function template to which a function template specialization refers:
- /1.1 during overload resolution for a call to a function template specialization ([over.match.best]);
- [...]
/2 Partial ordering selects which of two function templates is more specialized than the other by transforming each template in turn (see next paragraph) and performing template argument deduction using the function type. [...] If so, the more specialized template is the one chosen by the partial ordering process. If both deductions succeed, the partial ordering selects the more constrained template (if one exists) as determined below.
/3 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.
/4 Using the transformed function template's function type, perform type deduction against the other template as described in [temp.deduct.partial].
[temp.deduct.partial]
/2 Two sets of types are used to determine the partial ordering. For each of the templates involved there is the original function type
and the transformed function type. The deduction process uses the
transformed type as the argument template and the original type of the
other template as the parameter template. [...]
/4 Each type nominated above from the parameter template and the corresponding type from the argument template are used as the types of
P and A.
/8 Using the resulting types P and A, the deduction is then done as described in [temp.deduct.type]. [...] If deduction succeeds for a given type, the type from the argument template is considered to be at least as specialized as the type from the parameter template.
results in, for the original single function parameter function templates, the following P/A pairs:
P A
-------- ----------
#1: C<T> C<Unique1...>
#2: C<T...> C<Unique2>
Typically, when not in the context of partial ordering, deduction would succeed for both these pairs. However, [temp.deduct.type]/9 has a special case for when the deduction is performed as part of partial ordering:
/9 [...] During partial ordering, if Ai was originally a pack expansion:
- /9.2 otherwise, if Pi is not a pack expansion, template argument deduction fails.
This clause means deduction of #1
above (C<T>
from C<Unique1...>
) fails, whereas #2
(C<T...>
from C<Unique2>
) succeeds and C<Unique2>
is considered at least as specialized as C<T...>
. As per [temp.deduct.partial]/10 the non-variadic function template overload is thus at least as specialized as the variadic template function overload and, in the absense of the vice-versa relationsship, moreover more specialized:
/10 Function template F is at least as specialized as function template G if, for each pair of types used to determine the ordering,
the type from F is at least as specialized as the type from G. F is
more specialized than G if F is at least as specialized as G and G is
not at least as specialized as F.
This leads us back to [temp.func.order]/2 and the more specialized function template is chosen by partial ordering:
/2 [...] The deduction process determines whether one of the templates is more specialized than the other. If so, the more specialized template is the one chosen by the partial ordering process.
Which is also covered by [over.match.best]/2.5
/2 Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments
i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then
- [...]
- /2.5 F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2
according to the partial ordering rules described in
[temp.func.order], or, if not that, [...]