I was reading Thomas Becker\'s article on rvalue reference and their use. In there he defines what he calls if-it-has-a-name rule:
Things tha
Question 1: That rule is strictly referring to classifying expressions of rvalue reference type, not expressions in general. I almost agree with it in this context ('almost' because there's a bit more to it, see the quote below). The precise wording is in a note in the Standard [Clause 5 paragraph 7]:
In general, the effect of this rule is that named rvalue references are treated as lvalues and unnamed rvalue references to objects are treated as xvalues; rvalue references to functions are treated as lvalues whether named or not.
(emphases mine, for obvious reasons)
Question 2: As you can see from the other answers and comments (some nice examples in there), there are issues with general, concise statements about the value category of an expression. Here's the way I think about it.
We need to look at the problem from the other side: instead of trying to specify what expressions are lvalues, list the kinds that are rvalues; lvalues are everything else.
First, a couple of definitions to keep things clear:
Now, based primarily on [3.10] (but also quite a few other places in the Standard), an expression is an rvalue if and only if it is one of the following:
this, or literals like 7, not string ones);x.y, where x is an rvalue and y is a non-static member object;x.*y, where x is an rvalue and y is a pointer to a member object;x[y], where either x or y is an rvalue of array type (using the built-in [] operator).That's it.
Well, technically, the following special cases are also rvalues, but I don't think they're relevant in practice:
void, a cast to void, or a throw (obviously not lvalues, I'm not sure why I'd ever be interested in their value category in practice);obj.mf, ptr->mf, obj.*pmf, or ptr->*pmf (mf is a non-static member function, pmf is a pointer to member function); here we're talking strictly about these forms, not the function call expressions that can be built with them, and you really can't do anything with these but make a function call, which is a different expression altogether (to which we need to apply the rules above).And that's really it. Everything else is an lvalue. I find it easy enough to reason about expressions this way, as all categories above are easily recognizable. For example, it's easy to look at an expression, rule out the cases above, and decide it's an lvalue. Even for category 4, which has a longer description, the expressions are easily recognizable (I tried hard to make it a one-liner, but ultimately failed).
Expressions involving operators can be lvalues or rvalues depending on the exact operator being used. Built-in operators specify what happens in each case, but user-defined operator functions can change the rules. When determining the value category of an expression, both the structure of the expression and the types involved matter.
Notes:
this in the example refers to this the pointer value, not *this.int& f(int), the expression f(7) doesn't generate an object by value, so it doesn't fit in category 2; it does generate a reference, but it's not an rvalue reference, so category 3 doesn't apply either; the expression is an lvalue.int&& f(int), the expression f(7) generates an rvalue reference; category 3 applies here, so the expression is an rvalue.int f(int), the expression f(7) generates an object by value; category 2 applies here, the expression is an rvalue.int&& a, using the expression a doesn't generate an rvalue reference; it just uses an identifier of reference type. Category 3 doesn't apply, the expression is an lvalue.x->y is translated to (*x).y. *x is an lvalue (it doesn't fit in any of the categories above). So, if y is a non-static member object, x->y is an lvalue (it doesn't fit in category 4 because of *x and it doesn't fit in 6 because that one only talks about member functions).x.y, if y is a static member, then category 4 doesn't apply. Such an expression is always an lvalue, even if x is an rvalue (6 doesn't apply either, because it talks about non-static member functions).x.y, if y is of type T& or T&&, then it's not a member object (remember, objects, not references, not functions), so category 4 doesn't apply. Such an expression is always an lvalue, even if x is an rvalue and even if y is an rvalue reference.decltype, for example.All references are to N4140, the last C++14 draft before publication.
I first found the last two special rvalue cases here (everything's also in the Standard, of course, but harder to find). Note that not everything on that page is accurate for C++14. It also contains a very nice summary on the rationale behind the primary value categories (at the top).