Search code examples
c++rvalue-referencetemplate-argument-deductionforwarding-reference

Forwarding reference does not deduce to rvalue reference


First, this question has been asked by others, see this and this, but (I think) neither of them provides a satisfactory answer.

According to cppreference,

Before deduction begins, the following adjustments to P and A are made:

  1. If P is not a reference type, a) if A is an array type, A is replaced by the pointer type obtained from array-to-pointer conversion; b) otherwise, if A is a function type, A is replaced by the pointer type obtained from function-to-pointer conversion; c) otherwise, if A is a cv-qualified type, the top-level cv-qualifiers are ignored for deduction:
  2. If P is a cv-qualified type, the top-level cv-qualifiers are ignored for deduction.
  3. If P is a reference type, the referenced type is used for deduction.
  4. If P is an rvalue reference to a cv-unqualified template parameter (so-called forwarding reference), and the corresponding function call argument is an lvalue, the type lvalue reference to A is used in place of A for deduction

After these transformations, the deduction processes as described below (cf. section Deduction from a type) and attempts to find such template arguments that would make the deduced A (that is, P after adjustments listed above and the substitution of the deduced template parameters) identical to the transformed A, that is A after the adjustments listed above.

Using this rule, we look at the following code, with type_name from this answer:

template<typename T>
void foo(T && t) {
    std::cout << type_name<T>();
}

int main() {
    int a = 1;
    foo(std::move(a)); // int, not int&&
}

From rule 3, since P = T && is a reference type, the referenced type T is used for deduction, i.e. deduced A is T.

A is the type of std::move(a), which is a rvalue of type int &&. No transformation is applicable, so transformed A is int &&.

To make deduced A identical to transformed A, we shall have T = int &&.

But the code above shows T = int. Is this an inaccuracy of cppreference, or my misunderstanding?


Solution

  • Expressions can't have reference types, so the type of std::move(a) is int, not int &&.