与函数类似,lambda表达式也是一种可调用对象,但其可以定义在函数内部。《C++ Primer》中提到一个lambda表达式表示一个可调用的代码单元,可以将其理解为一个未命名的内联函数。本笔记参考《C++ Primer》,主要对C++ lambda表达式的用法进行一个简单的记录。
用法简介
当需要一个实现简单功能的可调用对象时,使用lambda表达式可以使得代码更为简洁。在一些泛型算法中可以直接传入lambda表达式自定义规则,比如sort第三个参数直接写个lambda表达式指定排序规则。
lambda表达式的形式如下:
即
捕获列表用来放置在lambda表达式所在函数中定义的需要传入lambda表达式的局部变量。其余部分的含义与函数定义中对应的部分相同。不过lamdba必须使用尾置返回。lambda表达式中,参数列表和返回类型可以省略,捕获列表(尽管可能为空)和函数体必须存在。调用lambda表达式的方法也与调用普通函数一样,使用调用运算符()
即可。
简单示例
简单的lambda表达式及调用示例如下,该示例捕获列表为空,没有参数列表和返回类型,函数体也仅仅是返回一个字符串。
auto fun = [] { return "Hello world!"; };
cout << fun() << endl;//输出Hello world!
参数传递
lambda表达式传递参数的方式也与函数类似,使用给定实参初始化形参,通常实参和形参类型必须匹配。下面给出一个示例。
auto fun = [](const string &s1, const string & s2) { return s1 + ' ' + s2; };
string s1 = "Hello";
string s2 = "world";
cout << fun(s1,s2) << endl;//输出Hello world
捕获列表的使用
通过捕获列表,我们可以在lambda表达式中使用lambda表达式所在函数中定义的局部变量。
值捕获和引用捕获
采用值捕获,被捕获的变量的值是在lambda创建时拷贝。下面的示例中,变量a在lambda创建时被捕获,完成了值的拷贝,因此当a的值改变后,再调用lambda发现并不起作用。
int a = 1;
auto fun = [a](int b) { return a + b; };
int b = 1;
cout << a << ' ' << b << endl;//输出1 1
cout << fun(b) << endl;//输出2
a += 1;
cout << a << ' ' << b << endl;//输出2 1
cout << fun(b) << endl;//输出2
引用捕获的示例如下
int a = 1;
auto fun = [&a](int b) { return a + b; };
int b = 1;
cout << a << ' ' << b << endl;//输出1 1
cout << fun(b) << endl;//输出2
a += 1;
cout << a << ' ' << b << endl;//输出2 1
cout << fun(b) << endl;//输出3
隐式捕获
使用隐式捕获,就可以不显式列出要在lambda表达式要捕获的变量,取而代之的是让编译器通过lambda表达式中的代码来推断使用的变量。在捕获列表中写个=
指示使用值捕获方式,写个&
指示使用引用捕获方式。
int a = 1;
auto fun = [=](int b) { return a + b; };//[]中写个=,使用值捕获方式
int b = 1;
cout << a << ' ' << b << endl;//输出1 1
cout << fun(b) << endl;//输出2
a += 1;
cout << a << ' ' << b << endl;//输出2 1
cout << fun(b) << endl;//输出2
int a = 1;
auto fun = [&](int b) { return a + b; };//[]中写个&,使用引用捕获方式
int b = 1;
cout << a << ' ' << b << endl;//输出1 1
cout << fun(b) << endl;//输出2
a += 1;
cout << a << ' ' << b << endl;//输出2 1
cout << fun(b) << endl;//输出3
可以混用显式捕获和隐式捕获。不过若隐式部分使用值捕获方式,则显式部分就不能用值捕获方式,反之,隐式部分使用引用捕获方式,则显式部分就不能用引用捕获方式。
int a = 1;
int b = 1;
auto fun = [&, b](int c) { return a + b + c; };
int c = 1;
cout << fun(b) << endl;//输出3
显式捕获和隐式捕获用同一种方式提示错误:
当然,要是不用隐式捕获,捕获列表中各变量的捕获方式就随便写。
尾声:就简单记录这么多,一般我自己也很少用到复杂的情况。