为什么返回非引用类型的函数表达式被认为是prvalues而不是xvalues

Why are function expressions returning non-reference types considered to be prvalues and not xvalues?

本文关键字:prvalues 认为是 xvalues 表达式 返回 引用类型 函数 为什么      更新时间:2023-10-16
标准中的§ 3.10.1.5prvalue表达式定义为:

-prvalue("纯"右值)是一个不是xvalue的右值。[示例:调用函数的结果返回类型不是引用的是prvalue。文字(如12、7.3e5或true)的值为也是一个prvalue。--结束示例]

因此函数foo()prvalue表达式:

class Foo {}; 
Foo foo() { return Foo{}; }

要初始化lvalue reference to a non-volatile const type/rvalue reference,初始化器表达式必须是(§ 5.2.1.1):

[…]一个xvalue(但不是位字段)、类prvalue、数组prvalue或函数lvalue和"cv1T1"参考是否与"cv2 T2"或[…]兼容

因此,

Foo &&rrFoo_ = foo(); 

是有效代码,其中rrFoo_绑定到临时对象,延长对象的生存期(§12.2):

类类型的临时变量是在各种上下文中创建的:将引用绑定到prvalue(8.5.3),返回一个prvalue(6.6.3),一个创建prvalue(4.1、5.2.9、5.2.11、5.4)的转换,抛出异常(15.1),以及在一些初始化中(8.5)

如上所述,忽略RVO,以下Foo类型对象的初始化将从默认构造对象复制一个临时的move构造。然后将用于复制移动的临时对象构建名为obj_foo:的最终对象

Foo obj_foo{ foo() }; 

因此,在这两种情况下,我们要么从中窃取,要么甚至延长临时对象的生存期。否则,临时对象将被销毁。

§3.10.1.2将x值定义为:

xvalue(一个"eXpiring"值)也指的是一个对象,通常在其生命周期即将结束时(因此资源可以被移动)。[…]

我想不出任何不创建临时对象的情况。所以我的问题是,为什么像foo()这样的函数表达式被认为是prvalue表达式,尽管它们至少与xvalues具有相似的性质?

给定int f1()int && f2(),则decltype(f1())intdecltype(f2())int &&。这样做的方法是指定f1()是一个prvalue,f2()是一个xvalue。decltype然后查看给定的表达式是prvalue、xvalue还是lvalue。如果f1()f2()都是x值,那么仍然需要以其他方式进行相同的区分。