lambda表达式(匿名函数)的组成:
-
捕获子句(在 c + + 规范中也称为lambda 引导)。
-
参数列表可有可无. (也称为lambda 声明符)
-
可变规范可有可无.
-
异常规范可有可无.
-
尾随-返回类型可有可无.
-
lambda 体。
lambda表达式以一对中括号开始,和函数定义一样,会有参数列表,有一个函数体,里面会有return语句
Lambda表达式一般不需要说明返回值(相当于auto),有特殊情况需要说明时,则应使用‘->’
每个lambda表达式都有一个全局唯一的类型,要精准捕捉lambda表达式到一个变量中,只能通过auto声明的方式
1 #include <iostream> 2 #include <algorithm> 3 #include <vector> 4 5 using namespace std; 6 7 int Foo(int a, int b) { 8 return a+b; 9 } 10 11 int main() { 12 // []捕获列表 ()参数列表 ->返回值 13 int c = [](int a, int b) ->int{ 14 //函数体 15 return a+b 16 }(1, 2); 17 18 //f为自动推导后的函数体类型 19 auto f = [](int a, int b) ->int{ 20 //函数体 21 return a+b 22 }; 23 24 c = f(1, 2); 25 26 return 0; 27 }
lambda作者认为所有的程序都可以归纳为lambda表达式,变为一个函数式
... //lambda作者认为所有的程序都可以归纳为lambda表达式,变为一个函数式 //lambda表达式内部可以嵌套 -- 函数式编程: int c = [](int n){ return [](int x){ return n+x; }(1); }(2); cout << c << endl; auto f = [](int n){ return [](int x){ return n+x; }; }; int c = f(1)(2); cout << c << endl; ...
mutable关键字
mutable关键字,表示可以修改按值传入的变量的副本(不是值本身),类似于不带const关键字的形参。使用mutable关键字后对按值传入的变量进行的修改,不会将改变传递到Lambda表达式之外。
例子:
int main() { int t = 10; auto f = [t]() { return ++t; }; return 0; }
error: cannot assign to a variable captured by copy in a non-mutable lambda
在捕获列表中,只是捕获了外界的t,在表达式内部,t还是const类型,不允许修改
... int main() { int t = 10; auto f = [t]() mutable{ return ++t; }; cout << f() << endl; cout << f() << endl; cout << t << endl; return 0; }
out:
t不会改变,因为i修改的是按值传入的副本,不会影响值本身。
为什么两次调用f(),返回值会传递。
捕获列表
捕获列表,可以理解为一个参数的类型,默认情况下lambda表达式内部在默认情况下是不能使用函数外部的变量,
捕获列表就可以起到传递外部数据的作用:
- [] 不捕获任何变量。
- [&] 捕获外部作用域中所有变量,并作为引用在函数体中使用(按引用捕获)。
- [=] 捕获外部作用域中所有变量,并作为副本在函数体中使用(按值捕获)。
- [=,&foo] 按值捕获外部作用域中所有变量,并按引用捕获 foo 变量。
- [bar] 按值捕获 bar 变量,同时不捕获其他变量。
- [this] 捕获当前类中的 this 指针,让 lambda 表达式拥有和当前类成员函数同样的访问权限。如果已经使用了 & 或者 =,就默认添加此选项。捕获 this 的目的是可以在 lamda 中使用当前类的成员函数和成员变量。
//进阶写法 for_each(v.begin(), v.end(), [](int n) { if(v[i] % 2 == 0) { cout << v[i] << "是偶数" <<endl; }else{ cout << v[i] << "是奇数" <<endl; } });