【问题标题】:Why forwarding return value is needed为什么需要转发返回值
【发布时间】:2019-06-02 16:23:12
【问题描述】:

在std::forward的doc中,给出了如下例子:

template<class T>
void wrapper(T&& arg)
{
    foo(forward<decltype(forward<T>(arg).get())>(forward<T>(arg).get()));
}

为什么这里需要转发返回值?和下面的代码有什么不同的情况:

template<class T>
void wrapper(T&& arg)
{
    foo(forward<T>(arg).get());
}

【问题讨论】:

  • 请参阅您在en.cppreference.com/w/cpp/utility/forward 中提到的行下方的激励示例。它指的是底层 get() 函数有 2 个实现的情况。一种可以修改成员值:int &amp; get() &amp; {return i;},另一种不能修改int get() &amp;&amp; {return i;}
  • @indeterminatelysequenced 我还是不明白。 forward&lt;T&gt;(arg).get()的类型不会和forward&lt;decltype(forward&lt;T&gt;(arg).get())&gt;的参数一样,那为什么这里需要forward呢?
  • 我也有同样的困惑。表达式forward&lt;T&gt;(arg).get() 已经在正确的值类别中,所以我想说没有必要转发。

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


【解决方案1】:

让我们分解可能性。 T::get 可以返回左值引用(左值表达式)、右值引用(xvalue 表达式)或纯右值。

forward 表达式会将左值表达式转换为...一个左值表达式。它会将 xvalue 转换为... xvalue。它会将prvalue转换为xvalue。

C++ 关于参数如何在重载决议中绑定到参数的规则相同 用于prvalue 和xvalue 表达式。所以最后两个总是调用同一个函数。

因此,外部forward 什么也没做。确实,这比什么都不做更糟糕。为什么?

因为 C++17 及更高版本中的纯右值保证了省略; xvalues 不。如果foo 按值获取参数,则附加的forward 将显示一个不必要的临时值,然后将其移动到参数中。如果类型比int 更复杂,那么您很有可能会损失一些性能。

所以不要转发你要直接作为函数参数传递的返回值。如果您需要将值存储在中间 auto&amp;&amp; 变量中,那么您需要转发它。但是,如果您是这样在原地进行操作,请不要这样做。

【讨论】:

  • 是的,这个例子是反模式
【解决方案2】:

The edit it was added in 声称这是第二个重载的示例:

template< class T >
constexpr T&& forward( typename std::remove_reference<T>::type&& t ) noexcept;

这个例子不是很好,因为它已经是一个右值。实际上,我认为第二个重载并不是那么有用,除了制作:

std::forward<decltype(expression)>(expression);

适用于所有表达式(包括expression 是否为右值),但std::forward 的大多数用例仅限于T&amp;&amp; 和auto&amp;&amp; 的左值。

【讨论】:

    猜你喜欢
    • 2012-10-08
    • 1970-01-01
    • 2019-07-20
    • 2019-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-17
    • 2011-07-19
    相关资源
    最近更新 更多