zoukankan      html  css  js  c++  java
  • 完美转发

    https://github.com/changkun/modern-cpp-tutorial/blob/master/book/zh-cn/03-runtime.md

     

    完美转发

    前面我们提到了,一个声明的右值引用其实是一个左值。这就为我们进行参数转发(传递)造成了问题:

    void reference(int& v) {
        std::cout << "左值" << std::endl;
    }
    void reference(int&& v) {
        std::cout << "右值" << std::endl;
    }
    template <typename T>
    void pass(T&& v) {
        std::cout << "普通传参:";
        reference(v); // 始终调用 reference(int& )
    }
    int main() {
        std::cout << "传递右值:" << std::endl;
        pass(1); // 1是右值, 但输出左值
    
        std::cout << "传递左值:" << std::endl;
        int v = 1;
        pass(v); // r 是左引用, 输出左值
    
        return 0;
    }

    对于 pass(1) 来说,虽然传递的是右值,但由于 v 是一个引用,所以同时也是左值。因此 reference(v) 会调用 reference(int&),输出『左值』。而对于pass(v)而言,v是一个左值,为什么会成功传递给 pass(T&&) 呢?

    这是基于引用坍缩规则的:在传统 C++ 中,我们不能够对一个引用类型继续进行引用,但 C++ 由于右值引用的出现而放宽了这一做法,从而产生了引用坍缩规则,允许我们对引用进行引用,既能左引用,又能右引用。但是却遵循如下规则:

    函数形参类型实参参数类型推导后函数形参类型
    T& 左引用 T&
    T& 右引用 T&
    T&& 左引用 T&
    T&& 右引用 T&&

    因此,模板函数中使用 T&& 不一定能进行右值引用,当传入左值时,此函数的引用将被推导为左值。更准确的讲,无论模板参数是什么类型的引用,当且仅当实参类型为右引用时,模板参数才能被推导为右引用类型。这才使得 v 作为左值的成功传递。

    完美转发就是基于上述规律产生的。所谓完美转发,就是为了让我们在传递参数的时候,保持原来的参数类型(左引用保持左引用,右引用保持右引用)。为了解决这个问题,我们应该使用 std::forward 来进行参数的转发(传递):

    #include <iostream>
    #include <utility>
    void reference(int& v) {
        std::cout << "左值引用" << std::endl;
    }
    void reference(int&& v) {
        std::cout << "右值引用" << std::endl;
    }
    template <typename T>
    void pass(T&& v) {
        std::cout << "普通传参:";
        reference(v);
        std::cout << "std::move 传参:";
        reference(std::move(v));
        std::cout << "std::forward 传参:";
        reference(std::forward<T>(v));
    
    }
    int main() {
        std::cout << "传递右值:" << std::endl;
        pass(1);
    
        std::cout << "传递左值:" << std::endl;
        int v = 1;
        pass(v);
    
        return 0;
    }

    输出结果为:

    传递右值:
    普通传参:左值引用
    std::move 传参:右值引用
    std::forward 传参:右值引用
    传递左值:
    普通传参:左值引用
    std::move 传参:右值引用
    std::forward 传参:左值引用
    

    无论传递参数为左值还是右值,普通传参都会将参数作为左值进行转发,所以 std::move 总会接受到一个左值,从而转发调用了reference(int&&) 输出右值引用。

    唯独 std::forward 即没有造成任何多余的拷贝,同时完美转发(传递)了函数的实参给了内部调用的其他函数。

    std::forward 和 std::move 一样,没有做任何事情,std::move 单纯的将左值转化为右值,std::forward 也只是单纯的将参数做了一个类型的转换,从现象上来看,std::forward<T>(v) 和 static_cast<T&&>(v) 是完全一样的。

  • 相关阅读:
    多多挣钱,多多攒钱。
    平安鸿运英才少儿教育金保障计划
    沙河订奶
    排序算法--参考
    《程序设计基础》考试大纲 复习-C语言
    There is no Action mapped for namespace [/demo1] and action name [doLogin] associated with context path [/SSO_same_domain]
    Android报错 The connection to adb is down, and a severe error has occured.
    解析库beautifulsoup
    request模块使用
    爬虫基本原理
  • 原文地址:https://www.cnblogs.com/diegodu/p/9156899.html
Copyright © 2011-2022 走看看