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