Understanding rvalue references

Why does it get transformed into int once inside the function body?

It doesn't; it's still a reference to an rvalue.

When a name appears in an expression, it's an lvalue - even if it happens to be a reference to an rvalue. It can be converted into an rvalue if the expression requires that (i.e. if its value is needed); but it can't be bound to an rvalue reference.

So as you say, in order to bind it to another rvalue reference, you have to explicitly convert it to an unnamed rvalue. std::forward and std::move are convenient ways to do that.

Also, why not std::move?

Why not indeed? That would make more sense than std::forward, which is intended for templates that don't know whether the argument is a reference.


I always remember lvalue as a value that has a name or can be addressed. Since x has a name, it is passed as an lvalue. The purpose of reference to rvalue is to allow the function to completely clobber value in any way it sees fit. If we pass x by reference as in your example, then we have no way of knowing if is safe to do this:

void foo(int &&) {}
void bar(int &&x) { 
    foo(x); 
    x.DoSomething();   // what could x be?
};

Doing foo(std::move(x)); is explicitly telling the compiler that you are done with x and no longer need it. Without that move, bad things could happen to existing code. The std::move is a safeguard.

std::forward is used for perfect forwarding in templates.


It's the "no name rule". Inside bar, x has a name ... x. So it's now an lvalue. Passing something to a function as an rvalue reference doesn't make it an rvalue inside the function.

If you don't see why it must be this way, ask yourself -- what is x after foo returns? (Remember, foo is free to move x.)


rvalue and lvalue are categories of expressions.

rvalue reference and lvalue reference are categories of references.

Inside a declaration, T x&& = <initializer expression>, the variable x has type T&&, and it can be bound to an expression (the ) which is an rvalue expression. Thus, T&& has been named rvalue reference type, because it refers to an rvalue expression.

Inside a declaration, T x& = <initializer expression>, the variable x has type T&, and it can be bound to an expression (the ) which is an lvalue expression (++). Thus, T& has been named lvalue reference type, because it can refer to an lvalue expression.

It is important then, in C++, to make a difference between the naming of an entity, that appears inside a declaration, and when this name appears inside an expression.

When a name appears inside an expression as in foo(x), the name x alone is an expression, called an id-expression. By definition, and id-expression is always an lvalue expression and an lvalue expressions can not be bound to an rvalue reference.