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()
的第一个重载。
现在我的问题:
使用(并且需要)第二次重载的有效场景是什么?
forward
的设计原理在N2951中有详细讨论。
本文档列出了 6 个用例:
第二次过载启用情况 B 和 C。A. 应该将左值作为左值转发。所有实现都通过 这个测试。但这并不是经典的完美转发模式。这 该测试的目的是表明实施 2 的失败 既定目标是阻止除完美转发之外的所有用例。
B. 应该将右值作为右值转发。与用例 A 一样,这是 身份转变,这是一个激励人心的例子 需要身份转换的地方。
C. 不应该将右值作为左值转发。此用例 演示了意外创建悬空的危险情况 参考。
D。应该将较少的简历限定表达式转发给更多的 cv 限定表达式。 涉及以下内容的激励用例 在转发期间添加 const。
E。应该将派生类型的表达式转发到可访问的、 明确的基本类型。 涉及转发的激励用例 派生类型到基类型。
F。应该不转发任意类型转换。此用例 演示了转发中的任意转换如何导致 悬空参考运行时错误。
本文继续提供每个用例的示例,这些示例太长,此处无法重复。
更新
我刚刚通过这 6 个用例运行了第一个重载的“解决方案”,这个练习表明第二个重载也启用了用例 F:不应转发任意类型转换。