Why does adding const turn a forwarding reference into an rvalue reference?

The official name is not universal reference, but forwarding reference. The Standard states that only rvalue references to cv-unqualified template parameters fall in this category:

14.8.2.1 Deducing template arguments from a function call [temp.deduct.call]

3 If P is a cv-qualified type, the top level cv-qualifiers of P’s type
are ignored for type deduction. If P is a reference type, the type
referred to by P is used for type deduction. A forwarding reference is
an rvalue reference to a cv-unqualified template parameter.
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. [ Example:

template <class T> int f(T&& heisenreference);
template <class T> int g(const T&&);
int i;
int n1 = f(i); // calls f<int&>(int&)
int n2 = f(0); // calls f<int>(int&&)
int n3 = g(i); // error: would call g<int>(const int&&), which
               // would bind an rvalue reference to an lvalue

— end example ]

Allowing const T&& to behave as forwarding references, would make it impossible to overload a template function who takes only an rvalue reference as parameter.

Update: as @HowardHinnant mentions in the comments, const T&& does have its uses (see also this Q&A).

Leave a Comment