Учитывая следующие правила сворачивания ссылок
-
T& &
→T&
-
T&& &
→T&
-
T& &&
→T&
-
T&& &&
→T&&
Из третьего и четвертого правил следует, что T(ref qualifer) &&
является тождественным преобразованием, т.е. T&
остается при T&
и T&&
остается при T&&
. Почему у нас есть две перегрузки для std::forward
? Не может ли следующее определение служить всем целям?
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
помогает гарантировать, что функция вызывается только для значений non const. Я не совсем уверен, нужен ли const_cast
, так как это не сама ссылка, которая const.
Так как forward
всегда вызывается с явными параметрами шаблона, нам нужно рассмотреть два случая:
-
forward<Type&>(val)
Здесь типT
вforward
будетT&
, поэтому возвращаемый тип будет преобразованием идентичности вT&
-
forward<Type&&>(val)
Здесь типT
вforward
будетT&&
, поэтому возвращаемый тип будет тождественным преобразованием вT&&
Итак, зачем нам нужны две перегрузки, как описано в http://en.cppreference.com/w/cpp/utility/forward?
Примечание. Я не уверен, что std::forward
когда-либо используется с типами const
, но я отключил forward
в этом случае, потому что я никогда не видел, чтобы он использовался так. Также перемещение семантики не имеет смысла и в этом случае.