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, "template argument" " substituting _Tp is an lvalue reference type"); 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 error A&& 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_RTTI protected: // 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. // This relies on _Sp_counted_ptr_inplace::_M_get_deleter. void* __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); } #else template<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
//new_allocator.h #if __cplusplus >= 201103L template<typename _Up, typename... _Args> void construct(_Up* __p, _Args&&... __args) { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
上面STL例子,還應用了可變參數模版和轉發參數包語法,需要進一步了解。本人水平有限,如果錯誤請指正謝謝。