xvalue/prvalue 类别真的很重要吗?
Does xvalue/prvalue category really matter?
创建 xvalue 的唯一方法是使用 static_cast 转换。
是的,according to standard 还有其他三种情况,但它们都需要另一个 xvalue。因此,为简单起见,我假设这是目前唯一的方法。
我们需要传递一些东西给 static_cast。我们称它为 «gizmo»。
不管 gizmo 到底是什么(左值或右值),static_cast 的结果将是对完全相同事物的右值引用(我的意思是它不会产生任何临时对象)。结果的值类别可以是 prvalue 或 xvalue(对于对象)。让我们考虑第二种情况。
我知道 xvalue 对于对象来说比 prvalue 要好得多,因为它具有动态类型;但奇怪的是,我不知道 «gizmo» 的任何动作,其产生的纯右值包含对同一事物的引用:它看起来像所有将 «gizmo» 转换为纯右值的动作(如 static_cast< T > 或传递给具有非引用结果的函数)将创建临时对象(调用复制构造函数等)。
总结一下,如果我们有对象类型的值,我们可以:
- 根据该值生成 xvalue
或
- 参考临时对象(可能是值的副本)生成纯右值*
也许真正重要的是右值引用实际上指的是(相同的东西或副本)而不是 xvalue/prvalue 类别?
如果是这样,我们可能会认为 static_cast< T&& > 只是保存对同一事物的引用的唯一方法,不再关心 xvalue/prvalue。不是吗?
- 当然,如果值已经是纯右值,我们没有义务做一些事情来获得纯右值,但在这种情况下动态类型不能丢失。所以,又和xvalue没有区别了。
例如,xvalue
和 prvalue
在使用 decltype
推导规则时很重要。 cppreference 说什么:
- a) 如果表达式的值类别是
xvalue
,则 decltype
产生 T&&
;
- b) 如果表达式的值类别是
lvalue
,则 decltype
产生 T&
;
- c) 如果表达式的值类别是
prvalue
,则 decltype
产生 T
.
这样一来,编译器就可以更好地提示即将出现的是哪种表达式。当然,它只是在处理表达式的语义意义上很重要。
示例:
struct A {};
int main() {
decltype(auto) a1 = A(); //prvalue, type of a1 is A
decltype(auto) a2 = std::move(A()); //xvalue, type of a2 is A&&
}
在此示例中使用 auto
,a1
和 a2
都将获得 A
作为类型。
创建 xvalue 的唯一方法是使用 static_cast
我们需要传递一些东西给 static_cast。我们称它为 «gizmo»。 不管 gizmo 到底是什么(左值或右值),static_cast 的结果将是对完全相同事物的右值引用(我的意思是它不会产生任何临时对象)。结果的值类别可以是 prvalue 或 xvalue(对于对象)。让我们考虑第二种情况。
我知道 xvalue 对于对象来说比 prvalue 要好得多,因为它具有动态类型;但奇怪的是,我不知道 «gizmo» 的任何动作,其产生的纯右值包含对同一事物的引用:它看起来像所有将 «gizmo» 转换为纯右值的动作(如 static_cast< T > 或传递给具有非引用结果的函数)将创建临时对象(调用复制构造函数等)。
总结一下,如果我们有对象类型的值,我们可以:
- 根据该值生成 xvalue
或
- 参考临时对象(可能是值的副本)生成纯右值*
也许真正重要的是右值引用实际上指的是(相同的东西或副本)而不是 xvalue/prvalue 类别? 如果是这样,我们可能会认为 static_cast< T&& > 只是保存对同一事物的引用的唯一方法,不再关心 xvalue/prvalue。不是吗?
- 当然,如果值已经是纯右值,我们没有义务做一些事情来获得纯右值,但在这种情况下动态类型不能丢失。所以,又和xvalue没有区别了。
xvalue
和 prvalue
在使用 decltype
推导规则时很重要。 cppreference 说什么:
- a) 如果表达式的值类别是
xvalue
,则decltype
产生T&&
; - b) 如果表达式的值类别是
lvalue
,则decltype
产生T&
; - c) 如果表达式的值类别是
prvalue
,则decltype
产生T
.
这样一来,编译器就可以更好地提示即将出现的是哪种表达式。当然,它只是在处理表达式的语义意义上很重要。
示例:
struct A {};
int main() {
decltype(auto) a1 = A(); //prvalue, type of a1 is A
decltype(auto) a2 = std::move(A()); //xvalue, type of a2 is A&&
}
在此示例中使用 auto
,a1
和 a2
都将获得 A
作为类型。