首页 > 代码库 > C++0x,std::move和std::forward解析

C++0x,std::move和std::forward解析

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  模版重载

因为存在模版重载机制,所以左值使用第一个版本,而右值选择第二个版本。

 

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例子,还应用了可变参数模版和转发参数包语法,需要进一步了解。本人水平有限,如果错误请指正谢谢。

C++0x,std::move和std::forward解析