目录
0.痛点需求:
1.lambda表达式背景
2、C++11 lambda语法
3、C++11 lambda表达式捕获列表
4、lambda表达式测试例子(帮助理解)
5、总结
6、lambda表达式修改外界捕获的值
在阅览AOSP源码时,特别高版本AOSP源码中的HIDL代码中,经常看到C++使用lambda表达式,函数并且特别长,总是搞得一头雾水,让许多C程序员望而却步。磨刀不误砍柴工,通过几个对lambda表示的语法、demo,来理解下lambda表达式的用法。
在C++11标准中引入了lambda表达式,一般用于定义匿名函数,使得代码更加灵活简洁。
lambda表达式与普通函数类似,也有参数列表、返回值类型和函数体,只是它的定义方式更简洁,并且可以在函数内部定义。
准确的来说,现在的所谓高级语言(java、python、erlang、C++等)的lambda表达式,都是从lisp及其方言发展过来的,在20十世纪五六十年代,lisp作为人工智能语言,lambda表达式一直它的专属,所以说lisp是lambda表示的始祖也不过为过。
便于理解:将lambda表达式看成一个函数即可。
1.C++11允许省略lambda表达式的返回值类型定义:auto f = [](int a){ return a + 1; };注意:
编译器可以根据return 语句自动推导出返回值类型。2.初始化列表时,不能用于返回值的自动推导:auto x1 = [](int i){ return i; }; // OK: return type is int
auto x2 = [](){ return { 1, 2 }; }; // failed: 无法推导出返回值类型此时需要显式给出具体的返回值类型。3.lambda表达式在没有参数列表时,参数列表是可以省略的:auto f1 = [](){ return 1; }; //OK
auto f2 = []{ return 1; }; // OK: 省略空参数表
lambda表达式还可以通过捕获列表捕获一定范围内的变量:
<1>.[]:不捕获任何变量。<2>.[&]:捕获外部作用域中所有变量,并作为引用在函数体中使用(按引用捕获)。<3>.[=]:捕获外部作用域中所有变量,并作为副本在函数体中使用(按值捕获)。<4>.[=,&foo]:按值捕获外部作用域中所有变量,并按引用捕获 foo 变量。<5>.[bar]:按值捕获bar变量,同时不捕获其他变量。<6>.[this]:捕获当前类中的this指针,就可以在lambda表达式访问成员函数和成员变量。
注意:如果使用了&或者=的话,就可以默认使用this指针访问成员函数。
#include
using namespace std;class A {
public:int count = 10;int tmp = 99;void func(int x, int y){// error,没有捕获外部变量,所以访问外界的count和tmp变量,会报错不允许访问.//auto x1 = []{ return count; };// OK,按值捕获所有外部变量:count和tmpauto x2 = [=]{printf("x2: count = %d\n",tmp);printf("x2: count = %d\n",this->count);return count + x + y;};printf("x2 = %d\n",x2());// OK,按引用捕获所有外部变量:count和tmpauto x3 = [&]{printf("x3: count = %d\n",tmp);printf("x3: count = %d\n",this->count);return count + x + y;};printf("x3 = %d\n",x3());// OK,捕获this指针:可以访问count和tmpauto x4 = [this]{printf("x4: this->tmp = %d\n",this->tmp);printf("x4: this->count = %d\n",this->count);return count;};printf("x4 = %d\n",x4());// error,虽然捕获了this指针,但是没有捕获x,y,但是却使用x,y,所以会报错.//auto x5 = [this]{ return count + x + y; };// OK,捕获this指针、x、yauto x6 = [this, x, y]{printf("x4: this->tmp = %d\n",this->tmp);printf("x4: this->count = %d\n",this->count);return count + x + y;};printf("x6 = %d\n",x6());// OK,捕获this指针,并修改成员的值auto x7 = [this]{ return count++; };}
};int main(){//1.最简单的lambda表达式:以中括号"[]"开头,没有函数名字的定义,像是一个匿名函数.auto f = [](int a)->int { return a + 1; };cout << " f(1) = "<< f(1) << endl;//2.//<1>.测试1[]{cout << "Lambda空" << endl;}();//<2>.测试2auto FuncAdd = [](int a, int b)->int {return a + b; };int xx = FuncAdd(2, 3);cout << "xx = " << xx << endl;//<3>.测试3:: []外部参数:值传递auto FuncMultiPly = [xx](int a)->int {cout << "xx = " << xx << endl;cout << "a + xx = " << a + xx << endl;return a + xx;};FuncMultiPly(23);//<4>.测试4: 隐式捕获变量bint b = 23;auto FuncHide = [&]{cout <<"b = "<< b << endl;};FuncHide();//3.lambda表达式访问外部变量A* aa = new A();aa->func(1,2);}
<1>.从上demo看到,lambda表达式捕获列表,lambda 表达式能够访问的外部变量
<2>. 默认状态下,lambda表达式无法修改通过复制方式(即传值方式)捕获的外部变量。
如果希望修改这些变量,需要使用引用方式进行捕获。
如下例子传值和传引用demo:
#include
using namespace std;int main(){int id1 = 10;int id2 = 50;//1.传值 auto f1 = [id1] () mutable {cout << "id1: " << id1 << endl;++id1;};f1(); cout << id1 << endl;//2.传引用auto f2 = [&id2] () mutable {cout << "id2: " << id2 << endl;++id2;};f2(); cout << id2 << endl;//3.带参数的lambda表达式int round = 2;auto f3 = [&](int tmp){cout << "tmp = " << tmp << endl;return tmp + round;} ;auto nn = f3(2);cout << "nn = " << nn << endl;return 0;
}