【问题标题】:Does an rvalue keep its "status" when a const reference parameter binds to it?当 const 引用参数绑定到右值时,它是否保持其“状态”?
【发布时间】:2019-03-23 19:51:44
【问题描述】:

T 是任意类型。考虑一个接受const [lvalue] 引用的函数:

void f(const T &obj);

假设该函数在内部调用另一个函数,该函数具有右值引用重载:

void g(T &&obj);

如果我们将右值传递给f,是否会调用g 的右值引用重载,或者由于它已“转换”/绑定到const 左值引用而无法调用?

类似地,如果f 调用了一个函数,该函数按值获取T 的实例,

void h(T obj);

T有一个移动构造函数,(即T(T &&);),是调用移动构造函数,还是调用复制构造函数?

总之,如果我们想确保在对右值调用f 时,右值引用被传递并保持其右值“状态”,我们是否必须为f 提供右值引用重载?

【问题讨论】:

    标签: c++ move-semantics rvalue-reference pass-by-const-reference


    【解决方案1】:

    值类别应用于表达式,而不是对象。 f 中的 obj 是左值表达式,因此将被视为左值表达式。注意g 中的obj 也是一个左值表达式;如果表达式是一个对象的名称,那么它就是一个左值。

    您所说的能力正是存在转发引用的原因:因此可以通过函数调用保留参数表达式的值类别的复制/移动方面。 f 必须成为template<typename T> void f(T&& t); 形式的模板,并且在将其传递给g 时必须使用std::forward

    【讨论】:

      【解决方案2】:

      当您将引用的名称用作表达式时,该表达式始终是左值。不管它是左值引用还是右值引用。使用左值还是右值初始化引用也没关系。

      int &&x = 1;
      f(x); // Here `x` is lvalue.
      

      所以在void f(const T &obj) {...} 中,obj 始终是左值,无论您作为参数传递什么。

      还要注意,值类别是在编译时确定的。由于f 不是模板,因此其中每个表达式的值类别都不能依赖于您传递的参数。

      因此:

      如果我们将右值传递给f,是否会调用g 的右值引用重载

      没有。

      如果f 调用了一个按值获取T 实例的函数,void h(T obj);T 有一个移动构造函数(即T(T &&);),是否会调用移动构造函数

      没有。

      总之,如果我们想确保在对右值调用f 时,右值引用被传递并保持其右值“状态”,我们是否必须为f 提供右值引用重载?

      提供重载是一种选择。请注意,在这种情况下,您必须在右值重载中显式调用 std::move

      另一个选项是使用转发引用,正如 Nicol Bolas 建议的那样:

      template <typename T> void f(T &&t)
      {
          g(std::forward<T>(t));
      }
      

      在这里,std::forward 本质上充当“有条件的move”。如果将右值传递给它,它会移动t,否则什么也不做。

      【讨论】:

        猜你喜欢
        • 2021-09-09
        • 2013-07-04
        • 1970-01-01
        • 2010-11-21
        • 1970-01-01
        • 2017-04-13
        • 1970-01-01
        • 2016-06-21
        • 2017-04-15
        相关资源
        最近更新 更多