• C++ 基础与深度分析 Chapter10 泛型算法(bind、lambada表达式、泛型算法的改进ranges)


    概述

    在这里插入图片描述
    很多算法允许通过可调用对象自定义计算逻辑的细节

    transform
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    如何定义可调用对象:

    • 函数指针:概念直观,但定义位置受限
      在这里插入图片描述
      c++不支持在函数内部定义函数,所以位置是受限的。

    • 类:功能强大,但书写麻烦
      通过操作符重载,为类定义可调用对象。

    • bind :基于已有的逻辑灵活适配,但描述复杂逻辑时语法可能会比较复杂难懂

    • lambda 表达式:小巧灵活,功能强大

    bind

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <numeric>
    #include <sstream>
    #include <iterator>
    #include <functional>
    using namespace std;
    
    bool MyPredict2(int val1, int val2)
    {
        return val1 > val2;
    }
    int main()
    {
        using namespace std::placeholders;
        std::vector<int> x{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        std::vector<int> y{};
        std::copy_if(x.begin(), x.end(), std::back_insert_iterator(y), std::bind(MyPredict2, _1, 3));
        for (auto p : y)
        {
            cout << p << ' '; // 4-10
            cout << endl;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <numeric>
    #include <sstream>
    #include <iterator>
    #include <functional>
    using namespace std;
    
    bool MyPredict2(int val1, int val2)
    {
        return val1 > val2;
    }
    int main()
    {
        using namespace std::placeholders;
        auto x = std::bind(MyPredict2, _1, 3); // _1代表调用x时,接收x的第1个参数
        x(50); // 50会作为MyPredict2的第1个参数
        cout << x(50) << endl; // 1 true
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <numeric>
    #include <sstream>
    #include <iterator>
    #include <functional>
    using namespace std;
    
    bool MyPredict2(int val1, int val2)
    {
        return val1 > val2;
    }
    
    bool MyAnd(bool val1, bool val2)
    {
        return val1 && val2;
    }
    int main()
    {
        using namespace std::placeholders;
        auto x1 = std::bind(MyPredict2, _1, 3); 
        auto x2 = std::bind(MyPredict2, 10, _1); 
        auto x3 = std::bind(MyAnd, x1, x2);
        cout << x3(5) << endl; // 1 意思为:3 < 5 < 10
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    调用 std::bind 时,传入的参数会被复制,这可能会产生一些调用风险
    用智能指针解决
    在这里插入图片描述
    可以使用 std::ref 或 std::cref 避免复制的行为
    在这里插入图片描述
    bind还有一个缺点,就是复杂逻辑很难看懂代码。

    std::bind_front ( C++20 引入): std::bind 的简化形式
    绑定第一个参数。
    在这里插入图片描述
    在这里插入图片描述

    lambada表达式

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    参数与函数体:

    int main()
    {
        auto x = [](int val) { return val > 3; }; // (函数形参) {函数体,多条语句,要用分号隔离}
        cout << x((5)) << endl; // 1, 5 > 3
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    int main()
    {
        auto x = [](int val) { return (val > 3) && (val < 10); }; 
        cout << x((5)) << endl; // 1
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述
    返回类型的自动推导c++11。如果引入更多的return语句,所有的return语句的类型必须是相同的,这是前提。

    int main()
    {
        auto x = [](int val) 
        {
            if (val > 3)
            {
                return 3.0;
            }
            else
            {
                return 1.5;
            }
        
        }; 
        cout << x((5)) << endl; // 3,自动推导x的类型是double
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    int main()
    {
        // 告诉编译器返回类型
        auto x = [](int val) -> float 
        {
            if (val > 3)
            {
                return 3.0;
            }
            else
            {
                return 1.5f;
            }
        
        }; 
        cout << x((5)) << endl; // 3
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    捕获: 针对函数体中使用的局部自动对象进行捕获

    int main()
    {
        int y = 10;
    
        auto x = [](int val)
        {
            return val > y; // 报错,在lambada表达式内部,不知道y是什么
        }; 
        cout << x((5)) << endl; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    int main()
    {
        int y = 10; // 局部自动对象
    
        auto x = [y](int val)
        {
            return val > y; // 把y放到[]内进行捕获
        }; 
        cout << x((5)) << endl; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    int main()
    {
        static int y = 10; // y是一个局部静态对象,不需要捕获,直接使用
    
        auto x = [](int val)
        {
            return val > y; 
        }; 
        cout << x((5)) << endl; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    值捕获

    int main()
    {
        int y = 10;
    
        auto x = [y] (int val) mutable
        {
            ++y;
            return val > y; 
        }; 
        cout << x((5)) << endl; 
        cout << y << endl; // 10 lambada对y的修改,不会传递到外部,因为是值捕获,y是复制到lambada内部
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    引用捕获

    int main()
    {
        int y = 10;
    
        auto x = [&y] (int val)
        {
            ++y;
            return val > y; 
        }; 
        cout << x((5)) << endl; 
        cout << y << endl; // 11 y是引用捕获
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    混合捕获

    int main()
    {
        int y = 10;
        int z = 3;
    
        // 对y进行引用捕获,对z进行值捕获 --> 混合捕获
        auto x = [&y, z] (int val) mutable 
        {
            ++y;
            return val > z; 
        }; 
        cout << x((5)) << endl; // 1
        cout << y << endl; // 11
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    如果lambada[捕获列表]里要捕获的值太多,这样就比价麻烦。大部分对象如果都是值捕获的,我们在[]里写个=。所有在{}使用的局部自动对象都值捕获了。我们也可以在[]中写入&,表示在{}使用的局部自动对象都引用捕获了。

    int main()
    {
        int y = 10;
        int z = 3;
    
        // []除了z是值捕获,其他都是引用捕获
        auto x = [&, z] (int val) mutable 
        {
            ++y;
            return val > z; 
        }; 
        cout << x((5)) << endl; 
        cout << y << endl; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    this 捕获

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <numeric>
    #include <sstream>
    #include <iterator>
    #include <functional>
    using namespace std;
    
    struct Str{
        auto fun()
        {
            int val = 3; // 局部自动对象
            // this 表示如果构造了Str对象,this就是一个指针,指向Str对象的地址
            auto lam = [val, this] ()  
            {
                return val > x;
            }; 
            return lam();
        }
        int x;
    };
    
    int main()
    {
        Str s;
        s.fun();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    初始化捕获( C++14 )

    int main()
    {
        int x = 3;
        // 初始化捕获,构造对象y,将x赋予y
        auto lam = [y = x](int val)
        {
            return val > y;
        };
        cout << lam(100) << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    int main()
    {
        int x = 3;
        int y = 10;
        // z是在编译期计算出来的
        auto lam = [z = x + y](int val)
        {
            return val > z;
        };
        cout << lam(100) << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    *this 捕获( C++17 )
    在这里插入图片描述
    说明符
    mutable

    int main()
    {
        int y = 3;
        auto lam = [y](int val) mutable
        {
            ++y; // 不能通过编译,除非加上mutable
            return val > y;
        };
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    constexpr (C++17)

    int main()
    {
        int y = 3;
        auto lam = [y](int val) constexpr
        {
            return val + 1; // 表示这个lam可以在编译期进行调用
        };
        constexpr int val = lam(100);
        cout << val << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    consteval (C++20)

    int main()
    {
        int y = 3;
        auto lam = [y](int val) consteval
        {
            return val + 1; // consteval只能在编译期调用
        };
        constexpr int val = lam(100);
        cout << val << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    lambada表达式的深入应用

    在这里插入图片描述
    捕获时计算

    int main()
    {
        int x = 3;
        int y = 5;
        // 捕获时计算
        auto lam = [z = x + y]()
        {
            return z;
        };
        lam();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    即调用函数表达式( Immediately-Invoked Function Expression, IIFE )

    int main()
    {
        int x = 3;
        int y = 5;
        // 捕获时计算
        const auto val = [z = x + y]()
        {
            return z;
        }(); // 即调用函数表达式( Immediately-Invoked Function Expression, IIFE )
        // 构造完lam,构造完,马上执行lam 表达式
        // 执行完的值,马上赋给val,不需要额外定义函数
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    使用 auto 避免复制( C++14 )

    int main()
    {
        auto lam = [](auto x)
        {
            return x + 1;
        };
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    int main()
    {
        std::map<int, int> m{{2, 3}};
        // 虽然用了引用,但是还是复制了
        auto lam = [](const std::pair<int, int>& p)
        {
            return p.first + p.second;
        };
        cout << lam(*m.begin()) << endl; // 5
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    int main()
    {
        std::map<int, int> m{{2, 3}};
        auto lam = [](const auto& p)
        {
            return p.first + p.second;
        };
        cout << lam(*m.begin()) << endl; // 5
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    Lifting ( C++14 )

    #include <iostream>
    #include <map>
    using namespace std;
    
    auto fun(int val)
    {
        return val + 1;
    }
    
    auto fun(double val)
    {
        return val + 1;
    }
    
    int main()
    {
        // auto x,来决定用哪个fun
        auto lam = [](auto x)
        {
            return fun(x);
        };
        cout << lam(3) << endl; // 4
        cout << lam(3.5) << endl; // 4.5
        // auto b = std::bind(fun, 3); // bind不知道调用哪个fun了
        // cout << b() << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    递归调用( C++14 )

    #include <iostream>
    #include <map>
    using namespace std;
    
    /*
    int factorial(int n)
    {
        return n > 1 ? n * factorial(n - 1) : 1;
    }*/
    
    int main()
    {
        // 这么写递归调用的lambada表达式会报错
        auto factorial = [](int n){
            return n > 1 ? n * factorial(n - 1) : 1;
        };
        cout << factorial(5) << endl; // 120
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    泛型算法的改进ranges

    在这里插入图片描述

    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <ranges>
    using namespace std;
    
    
    int main()
    {
        std::vector<int> x{1, 2, 3, 4, 5};
       //  auto it = std::ranges::find(x.begin(), x.end(), 3);
        auto it = std::ranges::find(x, 3);
        cout << *it << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述
    view并不是对输入的东西立即计算,而是需要的时候计算,把提升程序的性能。view模糊了容器和算法的概念了。

  • 相关阅读:
    Gateway入门
    【Vue】用Vue代码详细介绍computed计算属性的用法
    汽车级全保护型六路半桥驱动器NCV7708FDWR2G 原理、参数及应用
    探讨基于IEC61499开发类似LabVIEW图形编程工具
    “淘宝拍立淘图片搜索接口:轻松找到同款商品!
    第九章:最新版零基础学习 PYTHON 教程—Python 元组(第一节 -Python 元组)
    论语第二篇-为政
    Laravel 第九章 其它功能
    用 Golang 采集 Nginx 接口流量大小
    C++ 类
  • 原文地址:https://blog.csdn.net/weixin_43716712/article/details/125496000