书中“右值”和“右值引用”之间的混淆

Posted

技术标签:

【中文标题】书中“右值”和“右值引用”之间的混淆【英文标题】:Confusion between "rvalue" and "rvalue reference" in book 【发布时间】:2020-08-24 06:33:03 【问题描述】:

(我搜索了[c++]《c++中的函数式编程》一书,只给出了4个不相关的结果。)

我正在阅读Ivan Čukić 的C++ 中的函数式编程,在第118 页有一句话我不确定我是否理解。该部分是关于成员函数的右值和左值重载,句子如下,其中第二个重载是使用&&引用类型限定符的那个:

第二个重载将在允许您从中替代数据的对象上调用——临时对象和其他右值引用

我的疑惑是:

italic 中的部分首先让我感到困惑,就像 如果不是暂时的,它还能是什么?,但也许这只是因为我还没有'对什么是 xvalues 没有明确的理解; 粗体中的单词真的让我感到困惑,因为只有当我删除那个单词时,这句话才对我有意义。

下面的代码是为了支持我的理解。

确实,我的理解是,如果我说右值引用,我说的是一个函数参数(所以它有一个名字;例如:a in the free function f' s 声明)声明为对实际参数的右值引用,或者我已声明的变量(因此它有一个名称;例如:rr)作为对另一个变量的右值引用; (fwiw,两个引用的ed实体都必须是右值,否则引用不会绑定)。无论哪种情况,由于它有一个名称,因此在其上调用成员函数 f 会导致调用左值重载,不是吗?

所以这本书有什么用词错误还是我遗漏了什么?

#include <iostream>

struct A 
  void f() &   std::cout << "lvalue\n";  // const & in the book, but it shouldn't make any difference
  void f() &&  std::cout << "rvalue\n"; 
;

void f(A&& a)  a.f();  // a is an lvalue (of type rvalue ref to)

int main() 
  A a;          // "normal" object
  A&& rr = A; // rvalue reference to a temporary (with life extended)

  a.f();
  A.f(); // only here I expect the rvalue overload to be called, and this is the case
  f(A);
  rr.f();

【问题讨论】:

【参考方案1】:

粗体中的词真的让我感到困惑,因为只有当我删除那个词时,这句话才对我有意义。

我同意。 IMO 更准确地说,这句话应该是

第二个重载将在允许您替代数据的对象上调用 - 右值(右值或 xvalue)。

右值引用用于类型,右值用于value categories,它们是独立的东西。在这种情况下,调用哪个重载取决于值类别,即要调用的对象是左值还是右值,与它的类型无关。

斜体中的部分首先让我感到困惑,就像在如果不是暂时的,那还能是什么?但也许这只是因为我还没有'对什么是 xvalues 没有明确的理解;

是的,xvalues 也是 rvalues。鉴于 int x = 0; std::move(x) 是一个 xvalue 但它不是临时的。

【讨论】:

也许将 xvalues 视为就像左值一样是直观的(两者都是 glvalues 并且都引用现有对象),但唯一的区别是 intent。左值指的是您打算以后仍然可用的对象,而xvalue 指的是您不再“关心”的对象。 还要注意表达式从不有引用类型。任何具有引用类型的表达式(例如,当函数的返回类型作为引用类型给出时的函数调用)都会从其类型中删除该引用,并相应地调整其值类别。 @HTNW,非常感谢您提供支持您第二条评论的链接,因为它可以帮助我理解这个主题。 所以表达式std::move(x) 是对x 的右值引用类型,它的值类别是右值。我说的对吗? @ZuodianHu decltype 实际上给你表达式的类型! decltype 使用引用类型组合类型和值类别信息:prvalues 没有引用,lvalues 得到&amp;,xvalues 得到&amp;&amp;。我之前的评论直接基于the standard。 decltype“谎言”这一事实也取自the standard。

以上是关于书中“右值”和“右值引用”之间的混淆的主要内容,如果未能解决你的问题,请参考以下文章

右值引用,移动语义,完美转发

重新理解C11的右值引用

C11新特性右值引用&&

C++11 中的左值引用和右值引用的区别

右值引用的参数传递疑问(C++0x)

C++11 ——— 右值引用和移动语义