为什么std :: forward有两个重载? [英] Why does std::forward have two overloads?
问题描述
给出以下参考折叠规则
-
T& &
->T&
-
T&& &
->T&
-
T& &&
->T&
-
T& &&
->T&&
T& &
-->T&
T&& &
-->T&
T& &&
-->T&
T&& &&
-->T&&
第三和第四条规则暗示 T(ref qualifer)&
是身份转换,即 T&
停留在 T&
和 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<的唯一目的; T&
的用途是不进行复制。 enable_if
有助于确保仅在非const值上调用该函数。我不确定是否需要 const_cast
,因为不是引用本身就是常量。
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< Type&>(val)
这是forward <中的
T
的类型/ code>将是T&
,因此返回类型将是将身份转换为T&
-
forward< Type&&>(val)
这里的T $ c $的类型
转发
中的c>将为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
类型一起使用,但是我禁用了在这种情况下前进
,因为我从未见过这样使用过。同样,在这种情况下,移动语义也没有任何意义。
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)的< href = https://stackoverflow.com/a/29135875/2069064> answer 和纸张放在 std :: forward()
上。
A good place to start would be Howard Hinnant's answer and paper on std::forward()
.
您的实现可以正确处理所有 normal 用例( 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
前两种情况可能导致潜在地修改原本为<$ c $的对象c> 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.
这篇关于为什么std :: forward有两个重载?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!