首页 > 解决方案 > std::forward() 的右值引用重载的目的是什么?

问题描述

我正在尝试完美转发,我发现 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取决于传递给它的参数是左值还是右值。如果它是 type 的左值UT则推导为U&。如果是右值,T则推导为U.

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

现在我的问题:

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

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

解决方案


N2951forward中详细讨论了其设计原理。

本文档列出了 6 个用例:

A.应该将左值作为左值转发。所有实现都通过了这个测试。但这不是经典的完美转发模式。此测试的目的是表明实现 2 未能实现其既定目标,即阻止除完美转发之外的所有用例。

B.应该将右值作为右值转发。与用例 A 一样,这是一个身份转换,这提供了一个需要身份转换的激励示例。

C.不应右值作为左值转发。此用例演示了意外创建悬空引用的危险情况。

D. 应该将较少的 cv 限定表达式转发到更多 cv 限定的表达式。一个鼓舞人心的用例,涉及在转发期间添加 const。

E.应该将派生类型的表达式转发到可访问的、明确的基类型。一个涉及将派生类型转发到基本类型的激励用例。

F. 不应转发任意类型转换。此用例演示了正向中的任意转换如何导致悬空引用运行时错误。

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

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

更新

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


推荐阅读