C++11 新特性之lamda表达式
Lambda 表达式实际上就是提供了⼀个类似匿名函数的特性,⽽匿名函数则是在需要⼀个函
数,但是⼜不想费⼒去命名⼀个函数的情况下去使⽤的。
利⽤ lambda 表达式可以编写内嵌的匿名函数,⽤以替换独⽴函数或者函数对象,并且使代
码更可读。
从本质上来讲, lambda 表达式只是⼀种语法糖,因为所有其能完成的⼯作都可以⽤其它稍微
复杂的代码来实现,但是它简便的语法却给 C++ 带来了深远的影响。
从⼴义上说, lamdba 表达式产⽣的是函数对象。在类中,可以重载函数调⽤运算符(),此时
类的对象可以将具有类似函数的⾏为,我们称这些对象为函数对象(Function Object)或者
仿函数(Functor)。相⽐ lambda表达式,函数对象有⾃⼰独特的优势。
void func(int); void func(char *);
lambda 表达式⼀般都是从⽅括号[]开始,然后结束于花括号{},花括号⾥⾯就像定义函数那
样,包含了 lamdba 表达式体,⼀个最简单的例⼦如下:
// 定义简单的lambda表达式 auto basicLambda = [] { cout << "Hello, world!" << endl; }; basicLambda(); // 输出:Hello, world!
上⾯是最简单的 lambda 表达式,没有参数。如果需要参数,那么就要像函数那样,放在圆括
号⾥⾯,如果有返回值,返回类型要放在->后⾯,即拖尾返回类型,当然你也可以忽略返回类
型,lambda会帮你⾃动推断出返回类型:
// 指明返回类型,托尾返回类型 auto add = [](int a, int b) -> int { return a + b; }; // ⾃动推断返回类型 auto multiply = [](int a, int b) { return a * b; }; int sum = add(2, 5); // 输出:7 int product = multiply(2, 5); // 输出:10
最前边的 [] 是 lambda 表达式的⼀个很重要的功能,就是 闭包。
先说明⼀下 lambda 表达式的⼤致原理:每当你定义⼀个 lambda 表达式后,编译器会⾃动
⽣成⼀个匿名类(这个类当然᯿载了()运算符),我们称为闭包类型(closure type)。
那么在运⾏时,这个 lambda 表达式就会返回⼀个匿名的闭包实例,其实⼀个右值。所以,我
们上⾯的 lambda 表达式的结果就是⼀个个闭包实例。
闭包的⼀个强⼤之处是其可以通过传值或者引⽤的⽅式捕捉其封装作⽤域内的变量,前⾯的⽅
括号就是⽤来定义捕捉模式以及变量,我们⼜将其称为 lambda 捕捉块。例⼦如下:
int main() { int x = 10; // 复制捕捉x,lambda表达式⽆法修改此变 auto add_x = [x](int a) { return a + x; }; // 引⽤捕捉x,lambda表达式可以修改此变 auto multiply_x = [&x](int a) { return a * x; }; cout << add_x(10) << " " << multiply_x(10) << endl; // 输出:20 100 return 0; }
捕获的⽅式可以是引⽤也可以是复制,
但是具体说来会有以下⼏种情况来捕获其所在作⽤域中的变量:
[]:默认不捕获任何变量;
[=]:默认以值捕获所有变量;
[&]:默认以引⽤捕获所有变量;
[x]:仅以值捕获x,其它变量不捕获;
[&x]:仅以引⽤捕获x,其它变量不捕获;
[=, &x]:默认以值捕获所有变量,但是x是例外,通过引⽤捕获;
[&, x]:默认以引⽤捕获所有变量,但是x是例外,通过值捕获;
[this]:通过引⽤捕获当前对象(其实是复制指针);
[*this]:通过传值⽅式捕获当前对象;