std :: forward()的右值引用重载的目的是什么?

时间:2019-05-29 13:26:49

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

我正在尝试完美转发,发现 std::forward()需要两个重载:

过载nr。 1:

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

过载nr.2:

template <typename T>
inline T&& forward(typename 
std::remove_reference<T>::type&& t) noexcept
{
    static_assert(!std::is_lvalue_reference<T>::value,
              "Can not forward an rvalue as an lvalue.");
    return static_cast<T&&>(t);
}

现在,完美转发的典型场景是

template <typename T>
void wrapper(T&& e)
{
    wrapped(forward<T>(e));
}

当然,您知道在实例化wrapper()时,T取决于传递给它的参数是左值还是右值。如果它是类型U的左值,则将T推导为U&。如果是右值,则将T推导为U

在任何情况下-在wrapper()的范围内-e都是左值,因此它总是使用std::forward()的第一个重载。

现在我的问题:

使用(并且需要)第二次重载的有效方案是什么?

2 个答案:

答案 0 :(得分:13)

N2951中详细讨论了forward的设计原理。

该文档列出了6个用例:

  

A。 应将左值作为左值转发。所有实现均通过   这个测试。但这不是经典的完美转发模式。的   该测试的目的是为了表明实现2的失败   提出了防止除完美转发之外的所有用例的目标。

     

B。 应将一个右值作为右值转发。与用例A一样,这是   身份转换,这是一个激励人的例子   需要身份转换的地方。

     

C。 应该将右值作为左值转发。   表现出意外产生悬挂的危险情况   参考。

     

D。 应将较少的简历限定表达式转发给更多   符合简历要求的表达式。   在前进过程中添加const。

     

E。 应将派生类型的表达式转发给可访问的,   明确的基本类型。   派生类型转换为基本类型。

     

F。 应该转发任意类型的转换。这种情况   演示在远期潜在客户中如何进行任意转化   悬而未决的参考运行时错误。

第二次重载启用情况B和C。

本文继续提供了每个用例的示例,这些示例太冗长,无法在此处重复。

更新

我刚刚通过这6个用例运行了第一个重载的“解决方案”,此练习表明,第二个重载也启用了用例F:不应转发任意类型转换。

答案 1 :(得分:1)

这是第二次重载的一种非常普遍的用法:通用lambda。

[](auto&& x) {
    return f(std::forward<decltype(x)>(x));
}

没有第二次重载,代码将使用std::conditional_t<std::is_rvalue_reference_v<decltype(x)>, ...>

(请参阅Scott Meyer的C++14 Lambdas and Perfect Forwarding