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 ofTinforwardwill beT&and therefore the return type will be the identity transformation toT&forward<Type&&>(val)Here the type ofTinforwardwill 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.