为什么我的 forward_ 函数不适用于右值?

Mae*_*tro 7 c++ perfect-forwarding

我已经了解如何std::move工作并实现我自己的版本仅供练习。现在我试图了解如何std::forward工作:

到目前为止,我已经实现了这一点:

#include <iostream>


template <typename T>
T&& forward_(T&& x)
{
    return static_cast<T&&>(x);
}


/*template <typename T>
T&& forward_(T& x)
{
    return static_cast<T&&>(x);
}*/

void incr(int& i)
{
    ++i;
}

void incr2(int x)
{
    ++x;
}

void incr3(int&& x)
{
    ++x;
}

template <typename T, typename F>
void call(T&& a, F func)
{
    func(forward_<T>(a));
}


int main()
{

    int i = 10;
    std::cout << i << '\n';
    call(i, incr);
    std::cout << i << '\n';

    call(i, incr2);
    std::cout << i << '\n';

    call(0, incr3); // Error: cannot bind rvalue reference of type int&& to lvalue of type int.

    std::cout << "\ndone!\n";
}
Run Code Online (Sandbox Code Playgroud)

为什么我必须提供forward(T&)采用左值引用的重载版本?据我了解,转发引用可以根据其参数的类型产生左值或右值。因此,通常不需要将纯右值文字与采用右值引用类型的函数一起传递0给?!callincr3int&&forward<T>(T&)

  • 如果我取消注释该forward_(T&)版本,它可以正常工作!?

  • 我仍然很困惑:为什么如果我只使用该forward_(T&)版本,它是否适用于任何价值类别?那么让一个转发参考有forward_(T&&)什么意义呢?

  • 如果我取消注释采用左值引用的版本T&和采用转发引用的版本,T&&那么代码工作正常,并且我在两者中添加了一些消息以检查调用了哪个。结果是那个T&&从不叫!

      template <typename T>
      T&& forward_(T& x)
      {
          std::cout << "forward_(T&)\n";
          return static_cast<T&&>(x);
      }
    
      template <typename T>
      T&& forward_(T&& x)
      {
          std::cout << "forward_(T&&)\n";
          return static_cast<T&&>(x);
      }
    
    Run Code Online (Sandbox Code Playgroud)
  • 我的意思是在上面显示的驱动程序中运行相同的代码。

Hol*_*Cat 5

如果您手动指定(而不是让编译器推断它),则引用T&&将不再是转发引用。T如果T不是左值引用,则为T&&右值引用并且不接受左值。

例如,如果你这样做forward_<int>(...),则该参数是右值引用并且...只能是右值。

但如果您这样做forward_(...),则该参数是转发引用,并且...可以具有任何值类别。(虽然这样称呼它是没有意义的,因为forward_(x)它将具有与其自身相同的值类别x。)

  • @Maestro:基本问题是`call(T&amp;&amp; a, F func)`的*内部*,**`a`始终是*左值***。即使“call()”的参数作为右值到达,一旦它进入内部并被赋予名称“a”,它就是一个左值。`forward&lt;T&amp;&amp;&gt;(a)` 将左值中的类别放回到它到达时的类别。当到达“forward()”时,“a”始终是左值。 (3认同)