Why is a named rvalue reference an lvalue expression?
Asked Answered
A

3

7

I know that a named reference is an lvalue:

int x = 1;
int& ref1 = x;
int&& ref2 = std::move(x);

I've read the explanation — that is because we can take the address of those ref1 and ref2.

But when we take the address of a reference we actually take the address of the referenced object, don't we? So this explanation doesn't seem to be correct.

So why a named reference is an lvalue?

Algor answered 26/5, 2019 at 19:35 Comment(0)
M
5

Per [expr.prim.id.unqual] (8.1.4.1 Unqualified names):

[...] The expression is an lvalue if the entity is a function, variable, or data member and a prvalue otherwise; it is a bit-field if the identifier designates a bit-field ([dcl.struct.bind]).

Per [basic]/6:

A variable is introduced by the declaration of a reference other than a non-static data member or of an object. The variable's name, if any, denotes the reference or object.

The declaration

int&& ref2 = std::move(x);

is a "declaration of a reference other than a non-static data member." Therefore, the entity denoted by ref2 is a variable. So the expression ref2 is an lvalue.

Makebelieve answered 27/5, 2019 at 11:3 Comment(9)
By this article, link. what is the rhs? what is lhs - ref2?Authors
@Authors What is "rhs"? What is "lhs"?Makebelieve
rhs - right hand side, lhs - left hand side of the expression. So rhs - std::move(x), lhs is int&& ref2 or ref2.Authors
@Authors Thank you for answering your own question. :)Makebelieve
lhs - you said is lvalue. This article introduce this terms: lvalues, rvalues, glvalues, prvalues, xvalues. So what is rhs and lhs in this terms? More info about rhs, lhsAuthors
@Authors std::move(x) is an xvalue (thus also an rvalue).Makebelieve
@Authors BTW, of course I know that "rhs" means "right hand side." What I meant to ask was actually "What is the right hand side? What is the left hand side?" Sorry for the confusion.Makebelieve
Thanks! So static data member is a variable, while non-static data member is not a variable? What's the point?Algor
@Algor Well, I'm not sure. Maybe you can ask a new question.Makebelieve
I
3

That explanation is just a simplification. lvalues aren't defined by being "something you can take the address of", but by a specific set of rules about the value category of expressions. Those rules are carefully constructed so as to result in a self-consistent language in which everything fits together reasonably neatly.

That being said, the explanation does rather fit here, if you consider that by writing ref1, you're not really naming "the reference" but the thing being referred to. That's the magic of references: you're supposed to consider them name aliases rather than entities in their own right.

There are some abstraction leaks surrounding this (particularly, member references), but that's the gist.

You ought to forget about notions like "the reference is an lvalue" and instead think about expressions. Objects have types; expressions have value categories.

Inositol answered 27/5, 2019 at 11:18 Comment(1)
So every variable and every function is just defined to be an lvalue by the standard?Algor
A
-1

Here is an explanation from Scott Meyers's book "Effective Modern C++":

In fact, T&& has two different meanings. One is rvalue reference, of course. Such references behave exactly the way you expect: they bind only to rvalues, and their primary raison d’être is to identify objects that may be moved from.

void f(Widget&& param); // rvalue reference

Widget&& var1 = Widget(); // rvalue reference

auto&& var2 = var1; // not rvalue reference

template<typename T>
void f(std::vector<T>&& param); // rvalue reference

template<typename T>
void f(T&& param); // not rvalue reference

The other meaning for T&& is either rvalue reference or lvalue reference. Such references look like rvalue references in the source code (i.e., T&&), but they can behave as if they were lvalue references (i.e., T&). Their dual nature permits them to bind to rvalues (like rvalue references) as well as lvalues (like lvalue references). Furthermore, they can bind to const or non-const objects, to volatile or non-volatile objects, even to objects that are both const and volatile. They can bind to virtually anything. Such unprecedentedly flexible references deserve a name of their own. I call them universal references.

Authors answered 27/5, 2019 at 11:3 Comment(1)
The question asks why an expression consisting of an unqualified-id denoting a variable of an rvalue reference is an lvalue. Universal references are irrelevant here. The expression param is an lvalue regardless of whether T is deduced as a lvalue reference type or not. Sorry for downvote.Makebelieve

© 2022 - 2024 — McMap. All rights reserved.