rvalues 的概念变得更加普遍,rvalues 的本质被确定为没有别名。添加了一个共享此属性的新值类别 xvalues,并且在 C++11 之前存在的右值子集被重命名为纯右值(“纯右值”)。
我们现在想要的两个主要部门是:
- glvalue vs prvalue:glvalues是对象(=存储位置);prvalues 是传统的“临时”(但见下文)。
- 左值与右值:左值绑定到左值引用,右值绑定到右值引用。这种区别是定义引用和引用绑定如何工作所需的区别。
xvalue 既是左值又是右值。这反映了右值引用是一种执行左值到极值转换(通过强制转换std::move
)的方式,即具有用户定义的右值。通过将右值绑定到右值引用(现在是左值),它们还允许从右值到左值的另一个方向的转换。
C++17 通过将纯右值转换为不再是对象的“名义值”或“未实现的值”进一步完善了这个想法。在这张新图片中,只有 glvalues 是对象。然而,prvalue 可以具体化为对象,这被恰当地称为“prvalue-to-glvalue 转换” 。
这种考虑值类别的新方法意味着,如果你有一个函数T f();
,其中T
不是引用,那么表达式f()
本身就不是对象(因此不需要复制对象!),而是在需要时(例如,如果你说f().x
) ,创建一个对象并使用prvalue(=物化)进行初始化,以便允许成员访问。
也许总结一下 C++17 中存在的所有转换是有价值的:
“glvalue-to-prvalue”:这就是 C 所说的“左值转换”。示例:int a = 1; 1 + a;
加法表达式的第二个操作数是prvalue,通过glvalue到prvalue的转换获得a
。
“右值到左值”:由右值引用提供。示例:int && r = e
。这e
是一个右值表达式,并且r
是一个指定相同(或潜在物化)对象的左值。
“prvalue-to-glvalue”:这是prvalue的具体化,是预期的glvalue。
“lvalue-to-rvalue”:仅通过例如“lvalue-to-xvalue”实际可用std::move
,例如int a; static_cast<int&&>(a);
。
请注意,列表中出现的所有对都具有相同数量的字母——要么都具有一个字母,要么都具有两个。我认为这是您提出的替代方案所缺乏的精心挑选的分类法的结果。