在 C ++ 03 中,表达式是rvalue或lvalue 。
在 C ++ 11 中,表达式可以是:
两类已成为五大类。
我想这篇文章可能不是那么简短的介绍: n3055
整个大屠杀始于移动语义。一旦我们有可以移动而不是复制的表达式,突然很容易掌握规则要求区分可以移动的表达式,以及在哪个方向上。
根据我的猜测,基于草案,r / l 值的区别保持不变,只有在移动的东西变得混乱的情况下。
他们需要吗?如果我们希望放弃新功能,可能不会。但为了实现更好的优化,我们应该接受它们。
引用n3055 :
E
是指针类型的表达式,然后*E
是一个左值表达式参考对象或函数,其E
点。另一个例子,调用返回类型为左值引用的函数的结果是左值。 有问题的文件是这个问题的一个很好的参考,因为它显示了由于新命名法的引入而发生的标准的确切变化。
这些新的表达类别是什么?
FCD(n3092)有一个很好的描述:
- 左值(所谓的历史,因为左值可能出现在赋值表达式的左侧)指定一个函数或一个对象。 [示例:如果 E 是指针类型的表达式,则 * E 是指向 E 指向的对象或函数的左值表达式。另一个例子,调用返回类型为左值引用的函数的结果是左值。 - 末端的例子]
- xvalue(“eXpiring” 值)也指对象,通常接近其生命周期的末尾(例如,可以移动其资源)。 xvalue 是涉及 rvalue 引用的某些表达式的结果(8.3.2)。 [示例:调用返回类型为右值引用的函数的结果是 xvalue。 - 末端的例子]
- glvalue(“广义” 左值)是左值或 x 值。
- rvalue(历史上所谓的,因为 rvalues 可能出现在赋值表达式的右侧)是 xvalue,临时对象(12.2)或其子对象,或者是与对象无关的值。
- prvalue(“纯”rvalue)是一个不是 xvalue 的 rvalue。 [示例:调用返回类型不是引用的函数的结果是 prvalue。诸如 12,7.3e5 或 true 之类的文字的值也是 prvalue。 - 末端的例子]
每个表达式都属于此分类法中的基本分类之一:lvalue,xvalue 或 prvalue。表达式的此属性称为其值类别。 [注意:第 5 章中对每个内置运算符的讨论表明了它产生的值的类别以及它所期望的操作数的值类别。例如,内置赋值运算符期望左操作数是左值,右操作数是 prvalue 并产生左值作为结果。用户定义的运算符是函数,它们期望和产生的值的类别由它们的参数和返回类型决定。 - 注意
我建议你阅读3.10 Lvalues 和 rvalues的整个部分。
这些新类别如何与现有的左值和左值类别相关联?
再次:
C ++ 0x 中的右值和左值类别是否与它们在 C ++ 03 中的相同?
rvalues 的语义特别随着移动语义的引入而发展。
为什么需要这些新类别?
因此可以定义和支持移动构造 / 分配。
我将从你的上一个问题开始:
为什么需要这些新类别?
C ++ 标准包含许多处理表达式的值类别的规则。一些规则区分左值和右值。例如,当涉及到重载决策时。其他规则区分 glvalue 和 prvalue。例如,您可以使用不完整或抽象类型的 glvalue,但没有不完整或抽象类型的 prvalue。在我们使用这个术语之前,实际需要区分 glvalue / prvalue 的规则是指 lvalue / rvalue 和它们无意中是错误的还是包含了很多解释和例外的规则......“除非 rvalue 是由于未命名右值参考......“。因此,将 glvalues 和 prvalues 的概念作为自己的名称似乎是一个好主意。
这些新的表达类别是什么?这些新类别如何与现有的左值和左值类别相关联?
我们仍然有与 C ++ 98 兼容的术语 lvalue 和 rvalue。我们只是将 rvalues 分成两个子组,xvalues 和 prvalues,我们将 lvalues 和 xvalues 称为 glvalues。 Xvalues 是未命名的右值引用的一种新值类别。每个表达式都是以下三个中的一个:左值,右值,右值。维恩图看起来像这样:
______ ______
/ X \
/ / \ \
| l | x | pr |
\ \ / /
\______X______/
gl r
功能示例:
int prvalue();
int& lvalue();
int&& xvalue();
但也不要忘记命名的右值引用是左值:
void foo(int&& t) {
// t is initialized with an rvalue expression
// but is actually an lvalue expression itself
}