I have a little C++ question.
On the first pages of Effective Modern C++, there is an example:
class Widget {
public:
Widget(Widget&& rhs);
};
Also, there is a comment: 'rhs is an lvalue, though it has an rvalue reference type'.
I just understood nothing, to be honest. What does it mean 'rhs is an lvalue, but it's type is rvalue reference'?
Keep in mind that there are two distinct things here:
One is related to the type of variables: there are two types of references: lvalue references (
&
) and rvalue references (&&
).This determines what the function preferentially accepts and is always "obvious" because you can just read it from the type signature (or use
decltype
).The other is a property of expressions (or values): an expression can be an lvalue or an rvalue (actually, it's more complicated than that...).
This property is not manifest in the code directly (but there is a rule of thumb, see below), but you can see its effects in the overload resolution. In particular,
These properties are closely related (and in some sense "dual" to each other), but they don't necessarily agree with each other. In particular, it's important to realize that variables and expressions are actually different things, so formally speaking they aren't even comparable, "apples to oranges".
There is this rule in C++ that, even though you have declared
rhs
to be an rvalue reference (meaning that it will preferentially match arguments that are rvalues), within the block of move constructor, the variablerhs
itself will still behave as an lvalue, and thus preferentially match functions that accept lvalue references.The rationale for this was to prevent unintended moves within the move constructor.
The general rule of thumb is: if the expression has a name (i.e. consists of a single, named variable) then it's an lvalue. If the expression is anonymous, then it's an rvalue. (As dyp noted, this is not technically correct -- see his comment for a more formal description.)