std::move和std::forward仅仅是执行转换(cast)的函数(事实上是函数模板)。std::move无条件的将它的实参转换为右值,而std::forward只在特定情况满足时下进行转换。
std::move
template <class _Ty>
constexpr remove_reference_t<_Ty>&& move(_Ty&& _Arg) noexcept {
return static_cast<remove_reference_t<_Ty>&&>(_Arg);
}
std::move函数模板返回一个remove_reference_t<_Ty>&&,确保返回的一定是右值。
std::forward
template <class _Ty>
constexpr _Ty&& forward(remove_reference_t<_Ty>& _Arg) noexcept {
return static_cast<_Ty&&>(_Arg);
}
template <class _Ty>
constexpr _Ty&& forward(remove_reference_t<_Ty>&& _Arg) noexcept {
static_assert(!is_lvalue_reference_v<_Ty>, "bad forward call");
return static_cast<_Ty&&>(_Arg);
}
std::forward函数模板使用时显式指明模板参数类型,根据条件进行类型转换。
std::forward完美转发
void process(Widget& lval) {
std::cout << "左值process" << std::endl;
}
void process(Widget&& lval) {
std::cout << "右值process" << std::endl;
}
template<typename T>
void logAndProcess(T&& param) {
process(temp::forward<T>(param));
}
Widget w;
logAndProcess(w);
logAndProcess(Widget());
logAndProcess模板函数,使用通用引用的形式进行模板类型推导,如果传入左值,T
和Param
都会被推导为左值引用;如果传入右值,就正常推导,即T推导为Widget,param推导为Widget&&。
所以logAndProcess(w)函数体中,T为Widget&,param为Widget&,forward<T>(param)会调用forward(remove_reference_t<_Ty>& _Arg)版本的重载函数,返回static_cast<_Ty&&>(_Arg),根据引用折叠的规则,注意这里的_Ty为Widget&,Widget& && 就是Widget&,返回左值引用。
logAndProcess(Widget())函数体中,T为Widget,param为Widget&&,forward<T>(param)会调用forward(remove_reference_t<_Ty>&& _Arg)版本的重载函数,返回static_cast<_Ty&&>(_Arg),_Ty为Widget,所以返回Widget&&,即右值引用。
std::forward<Widget>(w) 和 std:forward<Widget&>(w)
std::forward<Widget>(w)返回右值,std:forward<Widget&>(w)返回左值,他们两个都会调用forward(remove_reference_t<_Ty>& Arg)版本的重载函数,因为_Ty类型的不同和引用折叠,一个返回右值,一个返回左值。
参考文章:https://cntransgroup.github.io/EffectiveModernCppChinese/5.RR...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。