Deduction Guide for Variation Pattern Designer Fails

I am trying to reproduce the result from a C ++ Weekly video - Ep 48 - C ++ 17 Variadic using , but failed. The problem can be simplified to the next part of the code.

Suppose I have such a general structure:

 template <class... T> struct Container { template <class... U> Container(U... us) {} }; 

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 . To solve this problem, we must provide a deduction guide, e.g.

 template <class... U> Container(U...) -> Container<double, int, bool> 

According to the video, the compiler should now know that d is of type Container<double, int, bool> .

However, the code is not working properly. When printing typeid(d).name() output will always be 9ContainerIJEE , which translates to Container<> , regardless of how I change the return type in the subtraction guide, indicating that such a guide does not direct the compiler at all.

I am using gcc-7-snapshot-20170402 , the compiler in the gcc-7-snapshot-20170130 .

Can someone tell me what's wrong here?

Update:

By the way, if I explicitly write

 Container<bool, int> d = Container(1,2,3); Container<char, char, char> d = Container(1,2,3); ... 

code will always compile and provide outputs like 9containerIJbiEE and 9containerIJcccEE .

+5
source share
1 answer

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 constructor template template <class... Us> Container<double, int, bool> f(Us... ); // the deduction guide f(1, 2, 3); // what does this return? 

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<> .

+3
source

Source: https://habr.com/ru/post/1266514/


All Articles