为什么命名右值引用是左值表达式?

Why is a named rvalue reference an lvalue expression?

我知道命名引用是左值:

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

我已经阅读了解释 — 那是因为我们可以获取那些 ref1ref2 的地址。

但是当我们获取引用的地址时,我们实际上获取的是被引用对象的地址,不是吗?所以这个解释似乎并不正确。

那么为什么命名引用是左值?

这是 Scott Meyers 的书 "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.

根据 [expr.prim.id.unqual](8.1.4.1 不合格名称):

[...] 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]).

根据 [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.

宣言

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

是一个"declaration of a reference other than a non-static data member."因此,ref2表示的实体是一个变量。所以表达式 ref2 是一个左值。

该解释只是一种简化。左值不是由 "something you can take the address of" 定义的,而是由一组关于表达式值类别的特定规则定义的。这些规则经过精心构建,以形成一种 self-consistent 语言,在这种语言中,一切都可以合理地整齐地组合在一起。

话虽这么说, 的解释很适合这里,如果您通过写作 ref1 来考虑这一点,那么您并不是真正在命名 "the reference",而是所指的事物。这就是引用的魔力:您应该将它们视为别名而不是实体本身。

围绕此存在一些抽象泄漏(特别是成员引用),但这就是要点。

您应该忘掉 "the reference is an lvalue" 这样的概念,而应该考虑 表达式 。对象有类型;表达式具有值类别。