简体   繁体   English

Rvalues,左值和正式定义

[英]Rvalues, lvalues and formal definitions

People are confused when they hear that in 人们在听到这些消息时会感到困惑

int&& x

x has rvalue reference type, but x is an lvalue. x具有右值引用类型,但x是左值。 Misunderstanding stems from the fact that identifiers and expressions are different things, and so are types and value categories. 误解源于标识符和表达式是不同的事实,类型和值类别也是如此。 Moreover, types of expressions are "adjusted prior to any further analysis", and the words "rvalue" and "lvalue" can appear both in type name and in value category name. 此外,表达式的类型是“在任何进一步分析之前调整”,单词“rvalue”和“lvalue”可以出现在类型名称和值类别名称中。

I want to clarify formal definitions. 我想澄清正式定义。 Suppose we have a function: 假设我们有一个功能:

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

Are the following statements correct? 以下陈述是否正确?

  1. In the line 1, x is an identifier (id-expression) that names a function parameter. 在第1行中, x是用于命名函数参数的标识符(id-expression)。 Its type is int&& , and this is the type that decltype(x) returns. 它的类型是int&& ,这是decltype(x)返回的类型。 x is not an expression and has no value category. x不是表达式,也没有值类别。
  2. In the line 2, x is an expression. 在第2行中, x是表达式。 Before type adjustment its type is int&& , and after the type becomes int . 在类型调整之前,它的类型是int&& ,在类型变为int The value category is lvalue. 值类别是左值。
  3. In the line 3, std::move(x) is an expression. 在第3行中, std::move(x)是一个表达式。 Its type before adjustment is int&& , after - int . 调整前的类型是int&& ,after - int The value category is xvalue. 值类别是xvalue。
  4. 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. 当我们说x具有右值引用类型时,我们将x的类型称为标识符,或者在类型调整之前将x的类型称为表达式。
  5. 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. 语句“每个表达式都有一些非引用类型,每个表达式恰好属于三个主要值类别之一”中的“type”一词在cppreference.com上是指类型调整后的类型。
  6. When Scott Meyers writes "If the type of an expression is an lvalue reference (eg, T& or const T& , etc.), that expression is an lvalue." 当Scott Meyers 写道 “如果表达式的类型是左值引用(例如, T&const T&等),则该表达式是左值。” he refers to the type before adjustment, and the second word "lvalue" refers to the value category. 他指的是调整前的类型,第二个单词“左值”指的是价值类别。

Some preliminary paragraphs first: 一些初步段落首先:

[basic] [基本]

3 An entity is a value, object, reference, function, enumerator, type, class member, template, template specialization, namespace, parameter pack, or this. 3实体是值,对象,引用,函数,枚举器,类型,类成员,模板,模板特化,命名空间,参数包或此。

[dcl.type.simple] [dcl.type.simple]

4 The type denoted by decltype(e) is defined as follows: 4decltype(e)表示的类型定义如下:

  • 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 . 如果e是未表示的id-expression或未表示的类成员访问([expr.ref]),则decltype(e)是由e命名的实体的类型。 If there is no such entity, or if e names a set of overloaded functions, the program is ill-formed; 如果没有这样的实体,或者如果e命名了一组重载函数,那么该程序就会形成错误;

  • otherwise, if e is an xvalue, decltype(e) is T&& , where T is the type of e ; 否则,如果e是x值,则decltype(e)T&& ,其中Te的类型;

  • otherwise, if e is an lvalue, decltype(e) is T& , where T is the type of e ; 否则,如果e是左值,则decltype(e)T& ,其中Te的类型;

  • otherwise, decltype(e) is the type of e . 否则, decltype(e)是的类型e

[dcl.ref] [dcl.ref]

1 In a declaration TD where D has either of the forms 1在宣言TDD有两种形式

\n& attribute-specifier-seq opt D1 attribute-specifier-seq opt D1 \n&& attribute-specifier-seq opt D1 && attribute-specifier-seq opt D1\n

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 .” 和在声明的标识符的类型T D1是“ 衍生的说明符类型列表 T ”,那么的标识符的类型D是“ 衍生的说明符类型列表参照T ”。

[expr] [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. 5如果表达式最初具有“对T引用”类型([dcl.ref],[dcl.init.ref]),则在进行任何进一步分析之前将类型调整为T The expression designates the object or function denoted by the reference, and the expression is an lvalue or an xvalue, depending on the expression. 表达式指定由引用表示的对象或函数,表达式是左值或x值,具体取决于表达式。

[expr.prim.general] [expr.prim.general]

8 An identifier is an id-expression provided it has been suitably declared (Clause [dcl.dcl]). 8 标识符是一个id表达式,只要它已被适当声明(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. 如果实体是函数,变量或数据成员,则结果是左值,否则为prvalue。

[expr.call] [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. 10如果结果类型是左值引用类型或对函数类型的右值引用,则函数调用是左值;如果结果类型是对象类型的右值引用,则为xvalue,否则为prvalue。

Which now allows us to answer your questions. 现在,我们可以回答您的问题。

In the line 1, x is an identifier (id-expression) that names a function parameter. 在第1行中, x是用于命名函数参数的标识符(id-expression)。 Its type is int&& , and this is the type that decltype(x) returns. 它的类型是int&& ,这是decltype(x)返回的类型。 x is not an expression and has no value category. x不是表达式,也没有值类别。

Yes of sorts. 是的。 x in the declaration is not an expression. 声明中的x不是表达式。 But as an argument to decltype is an expression. 但作为decltype一个参数一个表达式。 However, it hits the special case of decltype 's first bullet so the type of the identifier named by x is deduced, instead of the type of x as an expression. 但是,它遇到了decltype的第一个项目符号的特殊情况,因此推导出x所标识的标识符的类型,而不是x作为表达式的类型。

In the line 2, x is an expression. 在第2行中, x是表达式。 Before type adjustment its type is int&& , and after the type becomes int . 在类型调整之前,它的类型是int&& ,在类型变为int The value category is lvalue. 值类别是左值。

Yes. 是。

In the line 3, std::move(x) is an expression. 在第3行中, std::move(x)是一个表达式。 Its type before adjustment is int&& , after - int . 调整前的类型是int&& ,after - int The value category is xvalue. 值类别是xvalue。

Yes. 是。

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. 当我们说x具有右值引用类型时,我们将x的类型称为标识符,或者在类型调整之前将x的类型称为表达式。

Yes. 是。

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. 语句“每个表达式都有一些非引用类型,每个表达式恰好属于三个主要值类别之一”中的“type”一词在cppreference.com上是指类型调整后的类型。

Yes. 是。

When Scott Meyers writes "If the type of an expression is an lvalue reference (eg, T& or const T& , etc.), that expression is an lvalue." 当Scott Meyers写道“如果表达式的类型是左值引用(例如, T&或const T&等),则该表达式是左值。” he refers to the type before adjustment, and the second word "lvalue" refers to the value category. 他指的是调整前的类型,第二个单词“左值”指的是价值类别。

Can't really say for sure what Scott Meyers meant when he wrote this, but that is the only interpretation of the words that matches up with the standard, yes. 无法确切地说出斯科特迈耶斯写这篇文章时的意思,但这是与标准相符的唯一解释,是的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM