C++ std::move, std::forward
一、摘要
本文主要是针对std::move 和std::forward 转换原理和功能特性进行阐述,我比较喜欢从源码的方式进行,这个比较直观并且更能够明白实现细节
二、右值引用解析规则
转换规则1:
引用表达式 | 解析等价结果 |
---|---|
A& & | A& |
A& && | A& |
A&& & | A& |
A&& && | A&& |
引用转换规则2:
template<typename T>
void foo(T&&);
int a = 0;
foo(a); // 当传入参数为左值是,T 解析为 int& 在通过规则1 转换后变为int &
foo(0); // 当传入参数为右值时,T 解析为 int
三、std::move 和 std::forward源码解读
//remove_reference 改类的作用主要是移除模板解析的类型所附加的属性(&, &&)
template<class _Ty>
struct remove_reference
{ // remove reference
using type = _Ty;
};
template<class _Ty>
struct remove_reference<_Ty&>
{ // remove reference
using type = _Ty;
};
template<class _Ty>
struct remove_reference<_Ty&&>
{ // remove rvalue reference
using type = _Ty;
};
template<class _Ty>
using remove_reference_t = typename remove_reference<_Ty>::type;
//std::move 从源码上就可以看到无论传入参数是lvalue或rvalue该函数将会通过static_cast强制转换为rvalue
template<class _Ty>
constexpr remove_reference_t<_Ty>&&
move(_Ty&& _Arg) noexcept
{ // forward _Arg as movable
return (static_cast<remove_reference_t<_Ty>&&>(_Arg));
}
/*
*std::forward 相对要复杂一点可以分开进行分析(forward不支持类型自动推演方式,需要转换后强制指定类型)
*/
template<class _Ty>
constexpr _Ty&& forward(remove_reference_t<_Ty>& _Arg) noexcept
{ // forward an lvalue as either an lvalue or an rvalue
return (static_cast<_Ty&&>(_Arg));
}
template<class _Ty>
constexpr _Ty&& forward(remove_reference_t<_Ty>&& _Arg) noexcept
{ // forward an rvalue as an rvalue
static_assert(!is_lvalue_reference_v<_Ty>, "bad forward call");
return (static_cast<_Ty&&>(_Arg));
}
//demo 对forward转换原理进行描述
template<class T>
void foo(T && value)
{
std::forward<T>(value);
}
foo(3); //T 被解析为int, value 是lvalue 所以调用第一个函数 forward后得到的结果还是一个右值,等同于move
int a = 3;
foo(a); // T被解析为 int&,value是lvalue 所以调用第一个函数 forward后根据规则一forward转换后变为一个lvalue