zoukankan      html  css  js  c++  java
  • 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  模版重载

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

     

    更正:完美转发时 ,只有左值,因为右值引用一旦有名字,就是左值!!!必定选择第一个版本,在非完美转发场景下存在如下规则

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

  • 相关阅读:
    Java MVC和三层架构
    EL表达式
    EL表达式中的11个隐式对象
    JDBC连接数据库7个步骤
    JSP九大内置对象和四个作用域
    Eclipse常用快捷键大全
    Java的绝对路径和相对路径
    Servlet中相对路径与绝对路径
    mysql8的深坑
    mysql单列索引和联合索引
  • 原文地址:https://www.cnblogs.com/tangzhenqiang/p/4119267.html
Copyright © 2011-2022 走看看