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:
- 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:
- If P is a cv-qualified type, the top-level cv-qualifiers are ignored for deduction.
- If P is a reference type, the referenced type is used for deduction.
- 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?
Expressions can't have reference types, so the type of std::move(a)
is int
, not int &&
.