• lambda 表达式


    1. lambda 表达式的语法

    [捕捉列表] (参数列表) mutable ->return_type {函数体}

    • (参数列表) :与函数传参一致。不需要传递参数时,可以连同 () 省略。

    • mutable :传值捕捉时,mutable 可以取消参数的常性,使其在函数体内能被修改。不使用时,可以省略;使用该修饰符时,(参数列表) 不可省略(即使参数列表为空)。

    • ->return_type :函数体的返回值类型,通常可以省略,由编译器自行推导。

    C++11 中,最简单的 lambda 表达式为 []{},但它没有任何作用。

    1.2 lambda 用于sort的一个场景
    struct Goods
    {
        string _name;// 名称
        double _price;// 价格
        double _evaluations;// 评价
    
        Goods(const string& name, double price, double evaluations)
            :_evaluations(evaluations)
            , _price(price)
            , _name(name)
        {}
    };
    
    int main()
    {
        vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,3 }, { "菠萝", 1.5, 4 } };
    
        auto price = [](const Goods& g1, const Goods& g2) { return g1._price > g2._price; };
        auto evaluation = [](const Goods& g1, const Goods& g2) { return g1._evaluations > g2._evaluations; };
        
        // 按价格排降序
        sort(v.begin(), v.end(), price);
        // 按评价排降序
        sort(v.begin(), v.end(), evaluation);
    
        return 0;
    }
    

    通过以上场景,可以看出 lambda表达式 实际上是匿名仿函数

    2. 值传递捕捉/引用传递捕捉与 mutable

    2.1 值传递捕捉 和 mutable
    int main()
    {
        int x = 10, y = 20;
        // 值传递捕捉 x
        auto fun1 = [x] {
            // ++x; // “x”: 无法在非可变 lambda 中修改通过复制捕获
        };
        
        
        // 使用 mutable 时,(参数列表) 不可省略
        auto fun2 = [x]()mutable {
            // x += (y + 2);// 无法隐式捕获“y”,因为尚未指定默认捕获模式
            x += 2;
            cout << x << endl; 
        };
        fun2();// 函数体内的 x 是一个临时变量,
        cout << x << endl;// 修改函数体内的 x 不会改变 被捕捉的/函数体外的 x
        
        
        // 捕捉列表为 = 时,可以以值传递捕捉的方式,隐式捕捉当前作用域所有可访问的对象
        auto fun3 = [=] {
            return x*2 + y;
        };// 省略 ->return_type 时,编译器会自动推导
        int tmp = fun3();
        cout << tmp << endl;
        
        return 0;
    }
    
    2.2 引用传递捕捉
    int main()
    {
        int x = 10, int y = 20;
        
        // 引用传递捕捉 x
        auto fun1 = [&x] {
            ++x;
            cout << x << endl;
        };
        fun1();
        cout << x << endl;
        
        
        // 捕捉列表为 & 时,可以以引用传递捕捉的方式,隐式捕捉当前作用域所有可访问的对象
        auto fun2 = [&] {
            y++;
            x += y;
        };
        fun2();
        cout << x << endl;
        cout << y << endl;
        
        return 0;
    }
    

    PS:

    1. “当前作用域”:指包含该 lambda表达式的作用域。
    2. 语法上,捕捉列表可由多个捕捉对象组成,以逗号分割。
    int main()
    {
        int x, y;
        // 引用传递捕捉 x,值传递捕捉 y
        auto add_x = [&x, y](int a) mutable {
            cin >> y;
            x = y*2 + a;
        };
        add_x(10);
        
        return 0;
    }
    
    1. 捕捉列表不允许变量重复传递,否则会导致编译出错。
    int main()
    {
        int x = 1, y = 2;
        // [=, x] {};// 重复捕捉 x // error
        [=, &x] {}; // 引用传递捕捉 x,值传递捕捉当前作用域的其他可访问对象
        
        // [&, &x] {}; // error
        [&, x] {};// 值传递捕捉 x,引用传递捕捉当前作用域的其他可访问对象
        
        return 0;
    }
    
    1. 块作用域外的 lambda表达式 捕捉列表必须为空。
    auto func = [] {
        cout << "Hello World!" << endl;
    };
    
    int main()
    {
        func();
        return 0;
    }
    
    1. lambda表达式 之间不能相互赋值。
    int main()
    {
        auto f1 = [] { cout << "hello world!" << endl; };
        auto f2 = [] { cout << "hello world!" << endl; };
        // f2 = f1;// error
        
        auto f3(f1);
        
        return 0;
    }
    

    3. 函数对象 与 lambda表达式

    调用 f1() f2() 的反汇编:

    注意看:::operator()operator() 的方式不是类重载“函数调用运算符”吗?

    也就意味着,如果定义了一个 lambda表达式,编译器会自动生成一个类,重载 operator(),且 lambda表达式 的名称是编译器根据特定算法实时生成的、保证不重复。

    此处解释了,“为什么 lambda表达式 之间不能相互赋值”。

  • 相关阅读:
    金仓数据库KingbaseES安全指南--8.标记和强制访问控制
    (22杭电多校二)Two Permutation (dp),Package Delivery (贪心)
    深入理解 pytest Fixture 方法及其应用
    多线程 - 锁策略 & CAS
    Java实现---动态修改定时任务的执行时间
    Solon2 分布式事件总线的技术价值?
    猿创征文|高效能IT项目经理百宝箱中的五子良将
    MySQL数据类型
    赛码网的输入规则(Jsv8)
    python+人脸识别+opencv实现真实人脸驱动的阿凡达(上)
  • 原文地址:https://blog.csdn.net/taduanlangan/article/details/139809785