右值、左值和形式定义

Rvalues, lvalues and formal definitions

人们在

中听到这句话时感到困惑
int&& x

x 具有右值引用类型,但 x 是左值。误解源于这样一个事实,即标识符和表达式是不同的东西,类型和值类别也是如此。此外,表达式的类型是"adjusted prior to any further analysis","rvalue"和"lvalue"这两个词既可以出现在类型名称中,也可以出现在值类别名称中。

我想澄清正式的定义。假设我们有一个函数:

1 | void f(int&& x) {           
2 |     ... = x;               
3 |     ... = std::move(x);
4 | }

下列说法正确吗?

  1. 在第1行中,x是一个标识符(id-expression),它命名了一个函数参数。它的类型是int&&,这是decltype(x)returns的类型。 x 不是表达式,没有值类别。
  2. 第2行中,x是一个表达式。类型调整前为int&&,调整后为int。值类别是左值。
  3. 第3行中,std::move(x)是一个表达式。其调整前的类型为int&&,调整后为int。值类别为 xvalue.
  4. 当我们说 x 具有右值引用类型时,我们要么将 x 的类型称为标识符,要么将 x 的类型称为类型之前的表达式调整。
  5. cppreference.com处的语句"Each expression has some non-reference type, and each expression belongs to exactly one of the three primary value categories"中的单词"type"指的是类型调整后的类型。
  6. 当Scott Meyers writes "If the type of an expression is an lvalue reference (e.g., T& or const T&, etc.), that expression is an lvalue."他指的是调整前的类型,第二个字"lvalue"指的是值类别

先是一些初步的段落:

[basic]

3 An entity is a value, object, reference, function, enumerator, type, class member, template, template specialization, namespace, parameter pack, or this.

[dcl.type.simple]

4 The type denoted by decltype(e) is defined as follows:

  • if e is an unparenthesized id-expression or an unparenthesized class member access ([expr.ref]), decltype(e) is the type of the entity named by e. If there is no such entity, or if e names a set of overloaded functions, the program is ill-formed;

  • otherwise, if e is an xvalue, decltype(e) is T&&, where T is the type of e;

  • otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e;

  • otherwise, decltype(e) is the type of e.

[dcl.ref]

1 In a declaration T D where D has either of the forms

& attribute-specifier-seqopt D1 
&& attribute-specifier-seqopt D1

and the type of the identifier in the declaration T D1 is “derived-declarator-type-list T,” then the type of the identifier of D is “derived-declarator-type-list reference to T.”

[expr]

5 If an expression initially has the type “reference to T” ([dcl.ref], [dcl.init.ref]), the type is adjusted to T prior to any further analysis. The expression designates the object or function denoted by the reference, and the expression is an lvalue or an xvalue, depending on the expression.

[expr.prim.general]

8 An identifier is an id-expression provided it has been suitably declared (Clause [dcl.dcl]). The type of the expression is the type of the identifier. The result is the entity denoted by the identifier. The result is an lvalue if the entity is a function, variable, or data member and a prvalue otherwise.

[expr.call]

10 A function call is an lvalue if the result type is an lvalue reference type or an rvalue reference to function type, an xvalue if the result type is an rvalue reference to object type, and a prvalue otherwise.

现在我们可以回答您的问题了。

In the line 1, x is an identifier (id-expression) that names a function parameter. Its type is int&&, and this is the type that decltype(x) returns. x is not an expression and has no value category.

是的。声明中的 x 不是表达式。但是作为 decltype 的参数, 一个表达式。但是,它遇到了 decltype 的第一个项目符号的特殊情况,因此推导出由 x 命名的标识符的类型,而不是 x 的类型作为表达式。

In the line 2, x is an expression. Before type adjustment its type is int&&, and after the type becomes int. The value category is lvalue.

是的。

In the line 3, std::move(x) is an expression. Its type before adjustment is int&&, after - int. The value category is xvalue.

是的。

When we say that x has rvalue reference type, we refer either to the type of x as an identifier, or to the type of x as an expression before type adjustment.

是的。

The word "type" in the statement "Each expression has some non-reference type, and each expression belongs to exactly one of the three primary value categories" at cppreference.com refers to the type after type adjustment.

是的。

When Scott Meyers writes "If the type of an expression is an lvalue reference (e.g., T& or const T&, etc.), that expression is an lvalue." he refers to the type before adjustment, and the second word "lvalue" refers to the value category.

无法确定 Scott Meyers 写这篇文章时的意思,但这是对符合标准的词语的唯一解释,是的。