为什么 std::forward 有两个重载?
给定以下参考折叠规则
T&&
-->T&
T&&&
-->T&
T&&&
-->T&
T&&&&
-->T&&
T& &
-->T&
T&& &
-->T&
T& &&
-->T&
T&& &&
-->T&&
第三条和第四条规则意味着T(ref qualifer)&&
是恒等变换,即T&
停留在T&
code> 和 T&&
保持在 T&&
.为什么 std::forward
有两个重载?以下定义不能用于所有目的吗?
The third and fourth rule imply that T(ref qualifer) &&
is the identity transformation, i.e. T&
stays at T&
and T&&
stays at T&&
. Why do we have two overloads for std::forward
? Couldn't the following definition serve all purposes?
template <typename T, typename = std::enable_if_t<!std::is_const<T>::value>>
T&& forward(const typename std::remove_reference<T>::type& val) {
return static_cast<T&&>(const_cast<T&&>(val));
}
此处 const std::remove_reference
服务的唯一目的是不进行复制.并且 enable_if
有助于确保仅在非 const 值上调用该函数.我不完全确定是否需要 const_cast
因为它不是引用本身就是 const.
Here the only purpose the const std::remove_reference<T>&
serves is to not make copies. And the enable_if
helps ensure that the function is only called on non const values. I'm not entirely sure whether the const_cast
is needed since it's not the reference itself that's const.
由于 forward
总是使用显式模板参数调用,因此我们需要考虑两种情况:
Since forward
is always called with explicit template parameters there are two cases we need to consider:
forward
这里(val) forward
中T
的类型就是T&
因此返回类型将是到T&
的身份转换forward
这里 forward
中T
的类型就是T&&
因此返回类型将是到T&&
的身份转换
forward<Type&>(val)
Here the type ofT
inforward
will beT&
and therefore the return type will be the identity transformation toT&
forward<Type&&>(val)
Here the type ofT
inforward
will beT&&
and therefore the return type will be the identity transformation toT&&
那么为什么我们需要 http://en.cppreference 中描述的两个重载.com/w/cpp/utility/forward?
So then why do we need two overloads as described in http://en.cppreference.com/w/cpp/utility/forward?
注意:我不确定 std::forward
是否曾经与 const
类型一起使用,但我禁用了 forward
在那种情况下,因为我从来没有见过这样使用它.在这种情况下,移动语义也没有真正意义.
Note: I am not sure if std::forward
is ever used with const
types, but I disabled forward
in that case, because I have never seen it used like that. Also move semantics don't really make sense in that case either.
推荐答案
Howard Hinnant 的 answer 是一个很好的起点> 和 paper 关于 std::forward()
.
A good place to start would be Howard Hinnant's answer and paper on std::forward()
.
您的实现正确处理所有正常用例(T& --> T&
、T const& --> T const&
和 T&& --> T&&
).它无法处理的是常见且容易产生的错误,这些错误在您的实现中很难调试,但无法使用 std::forward()
进行编译.
Your implementation handles all the normal use-cases correctly (T& --> T&
, T const& --> T const&
, and T&& --> T&&
). What it fails to handle are common and easy-to-make errors, errors which would be very difficult to debug in your implementation but fail to compile with std::forward()
.
鉴于这些定义:
struct Object { };
template <typename T, typename = std::enable_if_t<!std::is_const<T>::value>>
T&& my_forward(const typename std::remove_reference<T>::type& val) {
return static_cast<T&&>(const_cast<T&&>(val));
}
template <class T>
void foo(T&& ) { }
我可以将非 const
引用传递给 const
对象,包括左值类型:
I can pass non-const
references to const
objects, both of the lvalue variety:
const Object o{};
foo(my_forward<Object&>(o)); // ok?? calls foo<Object&>
foo(std::forward<Object&>(o)); // error
和右值变量:
const Object o{};
foo(my_forward<Object>(o)); // ok?? calls foo<Object>
foo(std::forward<Object>(o)); // error
我可以将左值引用传递给右值:
I can pass lvalue references to rvalues:
foo(my_forward<Object&>(Object{})); // ok?? calls foo<Object&>
foo(std::forward<Object&>(Object{})); // error
前两种情况可能会修改原本是 const
的对象(如果它们被构造为 const
,则可能是 UB),最后一种情况是传递一个悬空左值引用.
The first two cases lead to potentially modifying objects that were intended to be const
(which could be UB if they were constructed const
), the last case is passing a dangling lvalue reference.
相关文章