Now I can initialize the container with any arguments, for example
auto d = Container(1,2,3);
However, the compiler will never know what type d .
This is not entirely accurate. Type d here Container<> . Letโs move away from the subtraction of the template for constructors and move on to simple function templates:
template <class... Ts, class... Us> void foo(Us... ); foo(1, 2, 3);
This function call is fine - we print Us as {int,int,int} , and we print Ts as {} . This is because of [temp.arg.explicit] / 3 :
The initial set of template template parameters, which otherwise is not displayed, will be displayed on an empty sequence of template arguments. If all template arguments can be inferred, they can be omitted; in this case, the empty list of template arguments <> may also be omitted.
Now, what package of parameters is the final template? This is unspecified. But here Ts... can be deduced as empty, so it is. Note that this has some odd values, for example:
template <class... Ts> void g(std::tuple<Ts...> ); g({}); // ok, calls g<>?
See also this brief discussion .
Returning to the original question. Ad
Container d(1, 2, 3);
without any residue instructions, it is well formed because we can succeed in outputting the template and display Ts... as empty. That is, it is exactly equivalent:
Container<> d(1, 2, 3);
So what happens when we add a deduction guide? Now we efficiently perform overload resolution between:
template <class... Ts, class... Us> Container<Ts...> f(Us... );
The selection teams in determining the best viable candidate are in [over.match.best] , where the following two are:
Given these definitions, a viable function F1 is defined as a better function than another viable function F2 if [...]
F1 and F2 are specialized function templates, and the function template for F1 more specialized than the template for F2 according to the partial order rules described in [temp.func.order], or, if not,F1 generated from the subtraction guide ([over.match.class.deduct]) and F2 not, or, if it is not, [...]
The private order of function templates is really pretty , and compilers do not quite agree on what to do in all cases. But in this case, I would say that this is a gcc error (I sent 80871 ). According to [temp.deduct.partial] :
The types used to determine the order depend on the context in which partial ordering is performed:
- In the context of a function call, those types of functions are used for which the function call has arguments.
That is, Ts... in the first function template (the one that was synthesized from the constructor) is not used for partial ordering. This makes both function templates the same, and therefore they are not more specialized than the others. Then we have to get into the next bullet, which says that we prefer the subtraction guide over the constructor and end with Container<double, int, bool> . gcc, however, for some reason believes that the first function template is more specialized and therefore selects it before getting into a tie-break for deduction, so it ends with Container<> .