【问题标题】:In std::forward how does it accept rvalue?在 std::forward 它如何接受右值?
【发布时间】:2015-03-13 20:20:02
【问题描述】:

查看 Scott Meyer 的 Effective Modern C++ 第 200-201 页,std::forward 的建议简化实现可能是(确实在其他地方看到了正确的实现):

template <typename T>
T&& forward(std::remove_reference_t<T>& param)
{ return static_cast<T&&>(param); }

而当接受一个右值Widget时,它变成:

Widget&& forward(Widget& param)
{ return static_cast<Widget&&>(param); }

现在,如果您使用该替代代码,然后执行以下操作:

struct Widget { };

Widget&& forward(Widget& param)
{ return static_cast<Widget&&>(param); }

template <typename T>
void G(T&& uref)
{ }

template <typename T>
void F(T&& uref)
{ G(forward(uref)); }

int main()
{
  Widget x;
  F(std::move(x));
}

我无法理解并且还没有看到关于 SO 的直接答案是:forward 中,参数Widget&amp; param 如何设法接受来自 F() 的 Widget&amp;&amp; ? 通常 gcc-5.0 会像这样抱怨非模板代码:

错误:从“std::remove_reference::type {aka Widget}”类型的右值初始化“Widget&”类型的非常量引用无效

Question #27501400 几乎触及了这个话题,但并不完全。它表明标准同时具有左值 & 和右值 && 版本。)

【问题讨论】:

  • 命名的右值引用是左值;真正的右值被单独的重载接受。
  • @T.C.这正是我忽略的方面,谢谢。
  • 如果它有名字,它就是一个左值。所以uref 是一个左值。
  • @JasonM 实际上,我已经通过电子邮件向 Scott 发送了完全相同的问题,因为我认为这是一个错误。他基本上忽略了右值重载,因为他想不出任何用例。我最近问过这个here

标签: c++ c++11 perfect-forwarding


【解决方案1】:

“命名的右值引用是左值”,

所以示例工作正常,如评论中所述。

不过你的代码可以修改为

template <typename T>
void F(T && uref)
{
    G(forward(move(uref)));
}

被另一个重载接受(比较):

template<typename T>
T && forward(typename std::remove_reference<T>::type & t)
{
    return static_cast<T &&>(t);
}


template<typename T>
T && forward(typename std::remove_reference<T>::type && t)
{
    static_assert(!std::is_lvalue_reference<T>::value, "T is an lvalue reference");
    return static_cast<T &&>(t);
}

第二个重载将用于右值。如果TWidgetWidget &amp;&amp; 并且Widget &amp; 的断言失败,则它可以工作。

【讨论】:

  • 为什么要将右值传递给std::forward
  • @0x499602D2 可能是偶然的。如果你这样做,你会得到一个 static_assert 错误。
猜你喜欢
  • 1970-01-01
  • 2015-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-15
  • 2015-05-22
  • 2016-07-08
  • 2015-07-09
相关资源
最近更新 更多