• Lambda函数


    1. 函数对象

       如果一个类将()运算符重载为成员函数,这个类就称为函数对象类,这个类的对象就是函数对象。函数对象是一个对象,

       但是使用的形式看起来像函数调用,实际上也执行了函数调用,因而得名。

    // 函数对象类
    class Average
    {
    public:
        // 重载()运算符
        double operator()(int a1, int a2, int a3) { return (double)(a1 + a2 + a3) / 3; }
    };
    
    int main()
    {
        Average average;           // 定义函数对象
        cout << average(3, 2, 3);  // 等价于 cout << average.operator(3, 2, 3);
        return 0;
    }
    

       因为调用形式很像函数,所以称之为函数对象,重载为成员函数的时候,有多少个参数都可以。

    2. lambda 表达式

       lambda表达式的大致原理:每当你定义一个 lambda 表达式后,编译器会自动生成一个匿名类(这个类当然重载了()运算符),我们称为

       闭包类型(closure type)。闭包意思就是封闭的函数。先举个例子:

    [&i] () { std::cout << i; }
    
    // 上面这个lambda会生成一个匿名类
    class anonymous
    {
    public:
        int &m_i; 
        anonymous(int &i) : m_i(i) {} 
        inline auto operator()() const { std::cout << i; }
    };

       Lambda 的语法形式如下:

    [函数对象参数] (操作符重载函数参数) mutable 或 exception 声明 -> 返回值类型 {函数体}
    

       1)mutable关键字:表示可以修改按值传入的变量的副本(不是值本身),类似于不带const关键字的形参。使用mutable关键字后对按值传入的变量进行

          的修改,不会将改变传递到Lambda表达式之外。

       2)[函数对象参数]:捕捉列表能够捕捉上下文中的变量以供 Lambda 函数使用。生成函数对象类的时候,会在类内部为这些捕获的变量进行定义,访问控制为private,

          并生成包含对应参数的构造函数,创建对象的时候就用捕获的外部变量作为形参来调用构造函数。

          []:不捕获任何变量

          [=]:捕获外部作用域中所有变量(包括lambda所在类的this),生成的构造函数是值传递方式。

          [&]:捕获外部作用域中所有变量(包括lambda所在类的this),生成的构造函数是引用传递方式。

          [this]:捕获当前类中的this指针,让lambda表达式拥有和当前类成员函数同样的访问权限,便于访问。如果已经使用了&或者=,则默认有此选项。

          [var]:将 var 按值进行传递,不引入其它变量。按值进行传递时,函数体内不能修改传递进来的 var 的拷贝,因为默认情况下函数是 const 的,要

                 修改传递进来的拷贝,可以添加 mutable 修饰符。

          [&var]:表示在Lambda表达式中,该变量使用以引用传递的方式捕获。

          [a,&b]:将 a 按值传递,b 按引用进行传递。

          [=,&a,&b]:除 a 和 b 按引用进行传递外,其他参数都按值进行传递。

          [&,a,b]:除 a 和 b 按值进行传递外,其他参数都按引用进行传递。

       3)(操作符重载函数参数):标识重载的 () 操作符的参数,没有参数时,这部分可以连同括号一起省略。

          参数可以通过按值(如: (a, b))和按引用 (如: (&a, &b)) 两种方式进行传递。

       4)->返回值类型:标识函数返回值的类型,当返回值为 void,或者函数体中只有一处 return 的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略。

       5){函数体}:标识函数的实现,这部分不能省略,但函数体可以为空。

       下面举几个例子:

    [] (int x, int y) { return x + y; }  // 隐式返回类型
    [] (int& x) { ++x; }                 // 没有 return 语句 -> Lambda 函数的返回类型是 'void'
    [] () { ++global_x; }                // 没有参数,仅访问某个全局变量
    [] { ++global_x; }                   // 与上一个相同,省略了 (操作符重载函数参数)
    [] (int x, int y) -> int { int z = x + y; return z; }
    

        总结:生成的匿名类 lambda_xxxx 与 lambda 表达式 的对应关系:

              a. lambda 表达式中的捕获列表,对应 lambda_xxxx 类的 private 成员

              b. lambda 表达式中的形参列表,对应 lambda_xxxx 类成员函数 operator() 的形参列表

              c. lambda 表达式中的 mutable,对应 lambda_xxxx 类成员函数 operator() 的常属性 const,即是否是 常成员函数

              d. lambda 表达式中的返回类型,对应 lambda_xxxx 类成员函数 operator() 的返回类型

              e. lambda 表达式中的函数体,对应 lambda_xxxx 类成员函数 operator() 的函数体

        另外,lambda 表达捕获列表的捕获方式,也影响 对应 lambda_xxxx 类的 private 成员的类型

              a. 值捕获:private 成员的类型与捕获变量的类型一致

              b. 引用捕获:private 成员 的类型是捕获变量的引用类型

      

  • 相关阅读:
    机器学习与深度学习资料
    JVM调优实战
    Spark on Yarn下JVM的OOM问题及解决方式
    Centos环境下部署游戏服务器-简介
    新华网,要厚道
    物联网操作系统在运营商领域推广的理论分析
    Android基础之Activity launchMode详解
    《高效程序员的修炼》读后感
    Java科普之算法剖析
    Java科普之基础知识回顾
  • 原文地址:https://www.cnblogs.com/yanghh/p/12971634.html
Copyright © 2020-2023  润新知