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

问题描述 投票:0回答:1

我正在尝试完美转发,我发现

std::forward()
需要两个重载:

过载次数。 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()
的第一个重载。

现在我的问题:

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

c++ c++11 c++14 c++17 perfect-forwarding
1个回答
14
投票

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

本文档列出了 6 个用例:

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

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

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

D。

应该将较少的简历限定表达式转发给更多的 cv 限定表达式。 涉及以下内容的激励用例 在转发期间添加 const。

E。

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

F。

应该转发任意类型转换。此用例 演示了转发中的任意转换如何导致 悬空参考运行时错误。

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

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

更新

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

© www.soinside.com 2019 - 2024. All rights reserved.