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 成员 的类型是捕获变量的引用类型

  

 

posted @ 2020-05-27 11:38  _yanghh  阅读(410)  评论(0编辑  收藏  举报