Given the following reference collapsing rules
T& &
-->T&
T&& &
-->T&
T& &&
-->T&
T&& &&
-->T&&
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));
}
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.
Since forward
is always called with explicit template parameters there are two cases we need to consider:
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&&
So then why do we need two overloads as described in http://en.cppreference.com/w/cpp/utility/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.