【问题标题】:Is std::move(a).m an xvalue or a prvalue?std::move(a).m 是 xvalue 还是 prvalue?
【发布时间】:2017-02-03 14:18:08
【问题描述】:

假设m 是非引用类型的非静态数据成员(T)。根据cppreferencestd::move(a).m 在 c++11 之前是一个prvalue。我想它应该是 c++11 之后的 xvalue。如果我错了,请纠正我。

但是decltype(std::move(a).m) 在 c++14 (visual studio, clang, gcc) 中仍然是T(不是T&&),这表明std::move(a).m 仍然是一个prvalue。那么std::move(a).m 是 xvalue 还是 prvalue?

【问题讨论】:

  • “我猜应该是c++11之后的xvalue” 为什么猜呢?同一篇文章明确指出了这一点。
  • decltype(std::move(a).m) 可能属于“无括号类成员访问表达式”special case
  • expression_name 可以告诉您编译器对此的看法:stackoverflow.com/a/20721887/576911 我的编译器同意 Barry。
  • 值类别“prvalue”在 C++11 之前不存在。只有左值和右值,而且,std::move 不存在。所以说move(a).m pre C++11 的值类别是没有意义的。

标签: c++11 c++14 decltype rvalue xvalue


【解决方案1】:

std::move(a).m 是一个 xvalue。

[basic.lval] 中的新措辞使这一点更加清晰:

  • prvalue 是一个表达式,它的求值初始化一个对象或一个位域,或者计算一个运算符的操作数的值,由它出现的上下文指定。
  • xvalue 是一个泛左值,表示其资源可以重复使用的对象或位域(通常是因为它接近其生命周期的终点)。

根据这些定义,std::move(a).m 是一个 xvalue 而不是 prvalue,因为它表示一个对象。

我认为最好的思考方式是,glvalues 具有标识,并且 rvalues 可以安全地从中移动 - 左值具有标识并且不安全地从中移动,xvalues 具有标识并且可以安全地从中移动,prvalues 可以没有身份并且可以安全地离开。这种分类法使这类问题更容易推理。

另外在[expr]中还有一个注解,比较具体:

[ 注意:一个表达式是一个 xvalue 如果它是:[...]
— 对对象类型的右值引用的强制转换,
— 类成员访问表达式,指定非引用类型的非静态数据成员,其中对象表达式是 xvalue,或 [...]
——尾注]

std::move(a) 是右值引用的强制转换,xvalue 也是。 std::move(a).m 是 xvalue 的类成员访问,xvalue 也是。


至于decltype(std::move(a).m)。请注意,这个词本身来自 declared typedecltype(e) 的含义规则很复杂,来自 [dcl.type.simple]:

对于表达式edecltype(e)表示的类型定义如下:
— 如果e 是一个不带括号的id-expression,它命名了从分解声明的identifier-list 引入的左值或引用,decltype(e) 是给定的引用类型在规范中 分解声明(8.5);
否则,如果e 是未加括号的id-expression 或未加括号的类成员访问(5.2.5), decltype(e)e 命名的实体的类型。如果不存在这样的实体,或者如果e 命名了一组重载函数,则程序格式错误;
— 否则,如果 e 是 xvalue,则 decltype(e)T&&,其中 Te 的类型;
— 否则,如果e 是左值,则decltype(e)T&,其中Te 的类型;
— 否则,decltype(e)e 的类型。

在这种情况下,我们有一个类成员访问权限,因此您只需获得 m 的类型 - 这是 M 而不是 M&&。在某种程度上,这是有道理的,您要求声明的类型为m,而声明的类型为m

如果您想对其进行正确分类,您可以使用一组额外的括号(显然)强制忽略该项目符号:decltype((std::move(a).m)) 会给您M&&

【讨论】:

  • 那么为什么T() 没有身份,而T().e 有呢?
  • @T.C.名字。 T() 没有名字,T().ee
  • @T.C.同样的想法。 [1] 用作名称。
  • 嗯。我根本看不出“[1] 是一个名字”比当前的描述更容易理解,尤其是。在一个你实际上并没有离开prvalues的世界里。
  • 当我不处理标准和极端情况时,我发现 C++11 Stroustrup 模型 +“保证省略”更容易。但是当我不得不使用后两者时(因此使用标准描述),我发现将它们混合起来比它的价值更麻烦。
猜你喜欢
  • 1970-01-01
  • 2018-07-08
  • 2017-09-12
  • 1970-01-01
  • 2013-06-25
  • 2021-01-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多