右值,左值和形式定义

Evg*_*Evg 12 c++ reference language-lawyer c++11 value-categories

人们听到他们的声音感到困惑

int&& x
Run Code Online (Sandbox Code Playgroud)

x具有右值引用类型,但x为左值。误解源于标识符和表达式是不同的事物,类型和值类别也是如此。此外,表达式的类型“在进行任何进一步分析之前已调整”,并且单词“ rvalue”和“ lvalue”可以同时出现在类型名称和值类别名称中。

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

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

以下陈述正确吗?

  1. 在第1行中,x是一个标识符(id表达式),它为函数参数命名。其类型为int&&,这是decltype(x)返回的类型。x不是表达式,没有值类别。
  2. 第2行x是一个表达式。在类型调整之前,其类型为int&&,而在类型变为之后int。值类别为左值。
  3. 在第3行中,std::move(x)是一个表达式。调整前的类型是int&&-之后int。值类别为xvalue。
  4. 当我们说它x具有右值引用类型时,在类型调整之前,我们将其x称为标识符,或者将其x称为表达式。
  5. cppreference.com上的语句“每个表达式都有一些非引用类型,每个表达式恰好属于三个主要值类别之一”中的单词“类型” 是指类型调整后的类型。
  6. 当斯科特·迈耶斯 Scott Meyers)写道: “如果表达式的类型是左值引用(例如T&const T&,等等),则该表达式是左值。” 他是指调整前的类型,第二个单词“左值”是指值类别。

Sto*_*ica 9

首先是一些初步的段落:

[基本]

3实体是值,对象,引用,函数,枚举器,类型,类成员,模板,模板专门化,名称空间,参数包或此。

[dcl.type.simple]

4用表示的类型decltype(e)定义如下:

  • 如果e是未括号化的id表达式或未括号化的类成员访问([expr.ref]),decltype(e)则是由命名的实体的类型e。如果没有这样的实体,或者如果e命名了一组重载函数,则程序格式错误;

  • 否则,如果e是xvalue,decltype(e)则是T&&,其中T的类型e

  • 否则,如果e是左值,decltype(e)则is T&,其中T的类型e

  • 否则decltype(e)为的类型e

[dcl.ref]

1在声明T DD具有以下两种形式之一

attribute-specifier-seq opt D1
&& 属性说明符-SEQ 选择 D1

并且声明中标识符的类型T D1为“ derived-declarator-type-list T ”,则标识符的类型D为“ derived-declarator-type-list引用T。”

[expr]

5如果表达式最初的类型为“对的引用T”([dcl.ref],[dcl.init.ref]),则将该类型调整为T在进行任何进一步分析之前。表达式指定由引用表示的对象或函数,并且表达式取决于表达式是左值还是x值。

[expr.prim.general]

8一种标识符是一个ID-表达,只要它已被适当地声明(第[dcl.dcl])。表达式的类型是标识符的类型。结果是由标识符表示的实体。如果实体是函数,变量或数据成员,则结果为左值,否则为prvalue。

[expr.call]

10如果结果类型是左值引用类型或对函数类型的右值引用,则函数调用为左值;如果结果类型是对对象类型的右值引用,则函数调用为xvalue;否则为prvalue。

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

在第1行中,x是一个标识符(id表达式),它为函数参数命名。其类型为int&&,这是decltype(x)返回的类型。x不是表达式,没有值类别。

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

第2行x是一个表达式。在类型调整之前,其类型为int&&,而在类型变为之后int。值类别为左值。

是。

在第3行中,std::move(x)是一个表达式。调整前的类型是int&&-之后int。值类别为xvalue。

是。

当我们说它x具有右值引用类型时,在类型调整之前,我们将其x称为标识符,或者将其x称为表达式。

是。

cppreference.com上的语句“每个表达式都有一些非引用类型,每个表达式恰好属于三个主要值类别之一”中的单词“类型”是指类型调整后的类型。

是。

当斯科特·迈耶斯(Scott Meyers)写道:“如果表达式的类型是左值引用(例如T&或const T&等),则该表达式是左值”。他是指调整前的类型,第二个单词“左值”是指值类别。

斯科特·迈耶斯(Scott Meyers)撰写本文时并不能真正确定是什么意思,但这是对与标准相符的单词的唯一解释,是的。

  • 如果您是一个类型,那么您将成为一个通用的参考,因为您在解释事物时非常灵活。 (4认同)