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:
Should gcc7 have deduced v
to be of type S<int&>
?
Where are described automatic deduction guide in the working draft standard?
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>;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With