1.std::move
1.1std::move是如何定义的
template<typename _Tp>constexpr typename std::remove_reference<_Tp>::type&&move(_Tp&& __t) noexcept{ return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }
1.2 std::move是如何工作的
1.2.1传入一个右值
a.如果传入是一个右值string,比如“hello”,推断出_Tp类型为string
b.std::remove_reference<_Tp>::type的类型依旧为string
c.move函数的返回类型为string&&
d.move函数的参数类型为string&&
e.static_cast显式转换类型为string&&
1.2.2传入一个左值
a.推断出_Tp的类型为string&
b.std::remove_reference<_Tp>::type的类型为string
c.move函数的返回类型为string&&
d.move函数的参数类型为string& &&,会折叠为string&
e.static_cast显式转换类型为string&&
1.3引用折叠
a.X& &,X& &&和X&& &都折叠为X&
b.X&& && 折叠为X&&
2.std::forward
2.1std::forward是如何定义的
/** * @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, );return static_cast<_Tp&&>(__t);}
2.2std::forward是如何工作的
2.2.1_Tp类型是左值引用
a.如果中转函数的实参是左值string,_Tp的类型为string&,std::remove_reference<_Tp>::type为string
b.forward函数参数__t的类型折叠后为string&
c.string& && (_Tp&&)折叠后依旧为左值引用string&
d.forword函数的返回为string&
2.2.2_Tp类型是右值
a.如果中转实参是右值sting,_Tp的类型为sting,std::remove_reference<_Tp>::type为string
b.forward函数参数__t的类型为string&&
c.forword函数的返回为string&&
2.3 模版重载
此处存在错误!因为存在模版重载机制,所以左值使用第一个版本,而右值选择第二个版本。
更正:完美转发时 ,只有左值,因为右值引用一旦有名字便是左值,所以必然选择第一个版本,在非完美转发场景下存在如下规则
A a;std::forward<A&>(std::move(a)); //版本 2 errorA&& a = std::forward<A&&>(A()); //版本 2 ok A&& b = std::forward<A>(A()); // 版本 2 ok
3.STL转发的例子
// shared_ptr.h // This constructor is non-standard, it is used by allocate_shared. template<typename _Alloc, typename… _Args>shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,_Args&&… __args): __shared_ptr<_Tp>(__tag, __a, std::forward<_Args>(__args)…){ } template<typename _Tp, typename _Alloc, typename… _Args>inline shared_ptr<_Tp>allocate_shared(const _Alloc& __a, _Args&&… __args){return shared_ptr<_Tp>(_Sp_make_shared_tag(), __a,std::forward<_Args>(__args)…);} template<typename _Tp, typename… _Args>inline shared_ptr<_Tp>make_shared(_Args&&… __args){typedef typename std::remove_const<_Tp>::type _Tp_nc;return std::allocate_shared<_Tp>(std::allocator<_Tp_nc>(),std::forward<_Args>(__args)…);}
//shared_ptr_base.h#ifdef __GXX_RTTIprotected:// This constructor is non-standard, it is used by allocate_shared.template<typename _Alloc, typename… _Args>__shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,_Args&&… __args): _M_ptr(), _M_refcount(__tag, (_Tp*)0, __a,std::forward<_Args>(__args)…){// _M_ptr needs to point to the newly constructed object.* __p = _M_refcount._M_get_deleter(typeid(__tag));_M_ptr = static_cast<_Tp*>(__p);__enable_shared_from_this_helper(_M_refcount, _M_ptr, _M_ptr);}#elsetemplate<typename _Alloc>struct _Deleter{void operator()(_Tp* __ptr){typedef allocator_traits<_Alloc> _Alloc_traits;_Alloc_traits::destroy(_M_alloc, __ptr);_Alloc_traits::deallocate(_M_alloc, __ptr, 1);}_Alloc _M_alloc;};template<typename _Alloc, typename… _Args>__shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,_Args&&… __args): _M_ptr(), _M_refcount(){typedef typename _Alloc::template rebind<_Tp>::other _Alloc2;_Deleter<_Alloc2> __del = { _Alloc2(__a) };typedef allocator_traits<_Alloc2> __traits;_M_ptr = __traits::allocate(__del._M_alloc, 1);__try{// _GLIBCXX_RESOLVE_LIB_DEFECTS// 2070. allocate_shared should use allocator_traits<A>::construct__traits::construct(__del._M_alloc, _M_ptr,std::forward<_Args>(__args)…);}__catch(…){__traits::deallocate(__del._M_alloc, _M_ptr, 1);__throw_exception_again;}__shared_count<_Lp> __count(_M_ptr, __del, __del._M_alloc);_M_refcount._M_swap(__count);__enable_shared_from_this_helper(_M_refcount, _M_ptr, _M_ptr);}#endif
所有欺骗中,自欺是最为严重的