鉴于以下参考折叠规则
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
有助于确保仅在非const值上调用该函数。我不完全确定const_cast
是否需要,因为它不是引用本身的常量。
由于始终使用显式模板参数调用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
,因为我从未见过就这样使用了。在这种情况下,移动语义也不是很有意义。
答案 0 :(得分:7)
一个好的起点是Howard Hinnant的answer和paper std::forward()
。
您的实现正确处理所有正常用例(T& --> T&
,T const& --> T const&
和T&& --> T&&
)。它无法处理的是常见且容易出错的错误,这些错误在您的实现中很难调试,但无法使用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
个对象,这两个对象都是左值:
const Object o{};
foo(my_forward<Object&>(o)); // ok?? calls foo<Object&>
foo(std::forward<Object&>(o)); // error
和rvalue变种:
const Object o{};
foo(my_forward<Object>(o)); // ok?? calls foo<Object>
foo(std::forward<Object>(o)); // error
我可以将左值引用传递给rvalues:
foo(my_forward<Object&>(Object{})); // ok?? calls foo<Object&>
foo(std::forward<Object&>(Object{})); // error
前两种情况导致可能修改意图为const
的对象(如果构造const
可能是UB),最后一种情况是传递悬空左值引用。