std::forward和std::move源码分析

原文:https://blog.csdn.net/kupepoem/article/details/119948044

一、右值引用

int和int&是什么?都是类型。int是整数类型,int&则是整数引用类型。同样int&&也是一个类型。两个引号&&是C++ 11提出的一个新的引用类型,右值引用类型,这是一个新的类型。如果你记住这个新类型,那么很多疑问都能迎刃而解。void G(A &&a) ,就很容易明白a是新类型右值引用的一个变量一个值,肯定是一个左值而不是右值。

二、forward源码分析

 /**
   *  @brief  Forward an lvalue.
   *  @return The parameter cast to the specified type.
   *
   *  This function is used to implement "perfect forwarding".
   */
  template
    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
    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);
    }

对于forward函数

std::forward(u)有两个参数:T与 u。

a. 当T为左值引用类型时,u将被转换为T类型的左值。比如T 为int&

b. 否则u将被转换为T类型右值。比如T为 int ,int &&

三、示例分析

1、不使用 std::forward

下述代码G不管传入什么类型的参数,只会最终调用 void F(int& a);

using namespace std;
 
void F(int& a) {
    cout << "int& version " <
void G(A &&a) {
    F(a); 
}
 
int main (int argc, char *argv[]) {
    int i = 2;
    G(i); //输出int& version
    G(5); //输出int& version
  return 0; 
}

G不管传入什么类型的参数,只会最终调用 void F(int& a)

这是为什么?

调用G(5)时,A被推导为int类型,但在G内部调用F(a)时,因为G函数中a是一个int &&的变量是个左值,调用F时编译译器自动推断调用 F(int & &&)类型的函数,根据引用折叠原理就会调用F(int & )c++引用折叠

调用G(i)时,A被推导为int &类型,根据引用折叠原理就会调用F(int & )。

2、用 std::forward

用 std::forward时,G的最终调用出现差异化

using namespace std;
 
void F(int& a) {
    cout << "int& version " <
void G(A &&a) {
    F(std::forward(a)); 
}
 
int main (int argc, char *argv[]) {
    int i = 2;
    G(i); //输出int& version
    G(5); //输出int&& version
 
  return 0; 
}

调用G(5)时,A被推导为int类型,但在G内部调用F(a)时,因为G函数中a是一个int &&的变量是个左值,调用std::forward(a)(std::forward(a)),A此时为int,强制转换为了右值。

调用G(i)时,A被推导为int &类型,调用std::forward(a)(std::forward(a)),还是强制转换成了左值。

四、std::move源码

头文件move.h

  template
    constexpr typename std::remove_reference<_Tp>::type&&
    move(_Tp&& __t) noexcept
    { return static_cast::type&&>(__t); }

可以看出std::move也是进行了强制类型转换,把一个左值强制转换成右值,没有新奇之处,参数__t的类型是万能引用(CSDN),可以接受不同类型的参数。

using namespace std;
 
void F(int& a) {
    cout << "int& version " <
void G(A &&a) {
    F(std::forward(a)); 
}
 
int main (int argc, char *argv[]) {
    int i = 2;
    G(std::move(i)); //输出int&& version
    G(5); //输出int&& version
 
  return 0; 
}

std::remove_reference

remove_reference源码
实现方式
这里的实现非常简单,就是去掉了类型的左值引用和右值引用,直接返回类型的基本内容。

性能开销
是否只在编译期间出现不会有任何运行时开销:是的。

/// remove_reference
template
struct remove_reference
{ typedef _Tp   type; };

template
struct remove_reference<_Tp&>
{ typedef _Tp   type; };

template
struct remove_reference < _Tp&& >
{ typedef _Tp   type; };

你可能感兴趣的:(std::forward和std::move源码分析)