C++11中的Lambda 表达式用于定义并创建匿名的函数对象,以简化编程工作。
Lambda简介
Lambda表达式一般都是从方括号[]开始,然后结束于花括号{},主要包括五个部分:
- [捕获列表 capture]:对外部变量的捕获方式说明,是必须的;
- (操作符重载函数参数 params):没有参数及修饰时可省略,是可选的;
- mutable 或 exception(指定Lambda表达式可以抛出的异常)声明:是可选的;
- -> 返回值类型:返回值为void,或函数体只有一处return(自动推断返回类型)可省略;
- {函数体 body}:表达式实现部分,是必须的;
常见几种Lambda表达式形式:
表达式 | |
---|---|
[ capture ] ( params ) mutable exception attribute -> ret { body } | (1) |
[ capture ] ( params ) -> ret { body } | (2) |
[ capture ] ( params ) { body } | (3) |
[ capture ] { body } | (4) |
- (1)是完整的Lambda表达式;
- (2)常见的Lambda表达式;
- (3)省略返回值的Lambda表达式:若有return语句,则据其推断返回类型;否则为无返回类型函数(
void f(…){}
); - (4)省略参数列表,生成无参数函数(
f(){}
);
如在sort函数中应用Lambda表达式:
std::sort(x, x + N,
// Lambda expression begins
[](float a, float b) {
return std::abs(a) < std::abs(b);
});
Capture列表
对于Lambda表达式,编译器会自动生成一个匿名类(重载()运算符
),称为闭包类型(closure type);在运行时,就返回这个匿名闭包类型的实例。闭包的一个强大之处是其可以通过传值或者引用的方式捕获其当前作用域内的变量,前面方括号就是用来定义捕获模式以及变量的,因此又将其称为Lambda捕获块。
Capture
是传递给闭包函数对象类的构造函数的:只能是那些Lambda表达式所在作用范围内可见的局部变量及其所在类的this指针。
- [=] 以值的方式捕获所有的可见的局部变量(包括Lambda所在类的 this)。
- [&] 以引用的方式捕获所有的外可见的局部变量(包括Lambda所在类的 this)。
- [a,&b] a变量以值的方式被捕获,b以引用的方式被捕获。
- [=, &foo] 以引用的方式捕获foo,以值方式捕获所有其他外部变量。
- [&, foo] 以值的方式捕获foo,以引用方式捕获所有其他外部变量。
- [this] 通过引用捕获当前对象(类的this指针)。
- [*this] 通过传值方式捕获当前对象;
注意:Capture并不能延长其捕获变量的生命周期,因此只捕获真正所需的变量,且避免悬挂引用的出现(在调用Lambda表达式时,引用变量因超出其声明域,而变的无效)。
mutable说明
默认情况下,使用值方式捕获的变量是不允许改变的(类似const成员变量),在闭包对象内永远保存的是其最初捕获时的值。若要对捕获的值进行修改,则需要使用mutable修饰,修饰后:
- 修改会累积:相当于修改类实例的成员变量;
- 修改不影响被捕获的外部变量的值;
如下所示:每次调用fun时都会累加fun对象内部的Count,但是外部的nCount一直保持原来的值(10)。
int nCount = 10;
auto fun = [nCount]()mutable {
++nCount;
cout << "In: " << nCount << endl;
};
fun();
fun();
cout << "Out: " << nCount << endl;
// In: 11
// In: 12
// Out: 10