C++之forward move源码分析
/**
* @brief Forward an lvalue.
* @return The parameter cast to the specified type.
*
* This function is used to implement "perfect forwarding".
*/
template<typename _Tp>
constexpr _Tp&&
forward(typename std::remove_reference<_Tp>::type& __t) noexcept
{ return static_cast<_Tp&&>(__t); }
/**
* @brief Forward an rvalue.
* @return The parameter cast to the specified type.
*
* This function is used to implement "perfect forwarding".
*/
template<typename _Tp>
constexpr _Tp&&
forward(typename std::remove_reference<_Tp>::type&& __t) noexcept
{
static_assert(!std::is_lvalue_reference<_Tp>::value, "template argument"
" substituting _Tp is an lvalue reference type");
return static_cast<_Tp&&>(__t);
}
主要说一下传入左值的情况,为啥返回的仍然是右值类型呢,说好的左值类型呢???
这里就涉及到一个折叠的概念,简单理解就是&的个数偶数就是右值,奇数就是左值。
明白了这个之后继续分析
比如说传入的是int&,那么 _Tp = int&,那么_Tp&&展开后int&&&。是不是豁然开朗。折叠后就是引用啊。
展开后的代码
int&& intForward(int && value)
{
return static_cast<int &&>(value);
}
int& intForward(int & value)
{
return static_cast<int &>(value);
}
明白了这个咱再看下move的实现
/**
* @brief Convert a value to an rvalue.
* @param __t A thing of arbitrary type.
* @return The parameter cast to an rvalue-reference to allow moving it.
*/
template<typename _Tp>
constexpr typename std::remove_reference<_Tp>::type&&
move(_Tp&& __t) noexcept
{ return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }
折叠之后的参数兼容了左值和右值,但是返回的时候是萃取到原始的类型,然后强制转换成右值进行返回。
展开后的代码
int&& intMove(int& value)
{
return static_cast<int&&>(value);
}
返回值为啥会有个typename呢,因为返回值用到的模板参数,通过typename告诉编译器后面是个数据类型,不是别的,求放过。不用typename的话,编译器就不能理解它后面那个是个啥东西,编译报错。
还用到了constexpr,这个是个啥呢,那就说来话长了。
篇幅有限,下次继续