为什么返回非引用类型的函数表达式被认为是prvalues而不是xvalues
Why are function expressions returning non-reference types considered to be prvalues and not xvalues?
§ 3.10.1.5
将prvalue
表达式定义为:
-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())
为int
,decltype(f2())
为int &&
。这样做的方法是指定f1()
是一个prvalue,f2()
是一个xvalue。decltype
然后查看给定的表达式是prvalue、xvalue还是lvalue。如果f1()
和f2()
都是x值,那么仍然需要以其他方式进行相同的区分。
- 为什么rand()的使用被认为是不好的
- 为什么 std::shared_ptr 被认为是"heavy"和"expensive",但 std::array "same perfprmance as plain (c-style) arrays
- 一个C头文件可以被认为是一个接口吗
- 为什么const char*和const char[]作为函数参数被认为是等价的
- 为什么12.0==11.999999999999999999被认为是真的
- 这会被认为是糟糕的编程实践吗?
- 为什么这被认为是恒定的?
- 抽象类/接口中的空方法是否被认为是一种好的做法?
- 如果我具有调用其其他实例之一的超载函数,它是否被认为是递归功能
- std::unique_ptr可以被认为是一个monad吗?
- C++ 指向类的指针和/或引用是否被认为是"movable"?
- 使用自定义宏来简化 cin 和 cout 语句等内容被认为是更好还是更差
- 使用成员函数更改对象或返回并分配它是否被认为是更好的做法?
- 我很难修复我认为是双重免费的东西
- 使用 #define 被认为是"bad practice"吗?
- 是一个被认为是不同类型的班级内部的正向声明
- 这被认为是有效的C 11还是C 14?还是GCC/Clang弄错了
- 为什么这个嵌套的 lambda 不被认为是 constexpr?
- 限制C++中允许的模板参数是否被认为是不良样式?
- 为什么返回非引用类型的函数表达式被认为是prvalues而不是xvalues