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,这个是个啥呢,那就说来话长了。

篇幅有限,下次继续

posted on 2021-09-11 23:11  奔跑吧,蜗牛!  阅读(129)  评论(0编辑  收藏  举报

导航