为什么需要转发返回值

Why forwarding return value is needed

本文关键字:返回值 转发 为什么      更新时间:2023-10-16

std::forward的文档中,它给出了以下示例:

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());
}

让我们分解一下可能性。T::get可以返回左值引用(即左值表达式)、右值引用(即 xValue 表达式)或 prvalue。

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

C++关于参数如何绑定到重载解析中的参数的规则对于 prvalue 和 xvalue 表达式是相同的。因此,最后两个将始终调用相同的函数。

因此,外在的forward什么也做不了。事实上,这比什么都不做更糟糕。为什么?

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

因此,不要转发将要直接作为函数参数传递的返回值。如果需要将值存储在中间auto&&变量中,则需要转发该值。但是,如果您像这样在原地进行,请不要这样做。

添加它的编辑声称它是第二个重载的示例:

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

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

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

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