Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Could an implicit template deduction guide deduce a reference type?

While testing C++17 deduction guide behaviour with gcc7, I found that this example fails:

template<class T>
struct S{
  S(T&& v){}
};
int i=10;
auto v = S(i);

According to what I have read from cpp reference, I thought v should be of type S<int &>. Nevertheless gcc7 does not compile this code complaining that a int& can not be bound to a int && (the universal reference mechanism fails).

So my questions are:

  1. Should gcc7 have deduced v to be of type S<int&>?

  2. Where are described automatic deduction guide in the working draft standard?

like image 320
Oliv Avatar asked Feb 05 '23 15:02

Oliv


1 Answers

The rule in [over.match.class.deduct] is:

A set of functions and function templates is formed comprising:
- For each constructor of the primary class template designated by the template-name, if the template is defined, a function template with the following properties:
    - The template parameters are the template parameters of the class template followed by the template parameters (including default template arguments) of the constructor, if any.
    - The types of the function parameters are those of the constructor.
    - The return type is the class template specialization designated by the template-name and template arguments corresponding to the template parameters obtained from the class template.

Our set includes:

template <class T> // <-- the template parameters come from the class template
S<T>               // <-- the return type is the class template specialization   
foo(T&& );         // <-- the types of the parameters are those of the constructor

We perform overload resolution as usual, which involves template deduction. But from [temp.deduct.call]:

A forwarding reference is an rvalue reference to a cv-unqualified template parameter that does not represent a template parameter of a class template (during class template argument deduction ([over.match.class.deduct])). If P is a forwarding reference and the argument is an lvalue, the type “lvalue reference to A” is used in place of A for type deduction.

Hence, this T&& is not a forwarding reference. It is an rvalue reference to T. So deduction against an lvalue (in our case, S(i)) fails. gcc is correct to reject your code here.

If you want the class template parameter to function as a forwarding reference, you will need to add a deduction guide:

template <class T> S(T&& ) -> S<T>;
like image 120
Barry Avatar answered Mar 06 '23 04:03

Barry