C++11常规特性之lambda

很多语言都提供了 lambda 表达式,如 Python,Java 8。lambda 表达式可以方便地构造匿名函数,如果你的代码里面存在大量的小函数,而这些函数一般只被调用一次,那么不妨将他们重构成 lambda 表达式。举一个例子。标准 C++ 库中有一个常用算法的库,其中提供了很多算法函数,比如 sort() 和 find()。这些函数通常需要提供一个“谓词函数 predicate function”。所谓谓词函数,就是进行一个操作用的临时函数。比如 find() 需要一个谓词,用于查找元素满足的条件;能够满足谓词函数的元素才会被查找出来。这样的谓词函数,使用临时的匿名函数,既可以减少函数数量,又会让代码变得清晰易读。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
mutable:当capture为传值的时候,函数不能修改外部的局部变量,如果需要修改,可以使用该关键字,
但是由于是传值,即使修改,也不会影响到capture的变量;传引用的时候,是可以修改变量的
而且会影响到所capture的变量
exception:说明 lambda 表达式是否抛出异常(noexcept),以及抛出何种异常,类似于void f() throw(X, Y)。
attribute: 用来声明属性
returnType: lambda函数的返回类型,可以不需要,lambda可以根据返回表达式自己推导
mutable exception attribute三个属性可以省略

capture 指定了在可见域范围内 lambda 表达式的代码内可见得外部变量的列表,具体解释如下:
[a,&b] a变量以值的方式呗捕获,b以引用的方式被捕获。
[this] 以值的方式捕获 this 指针。
[&] 以引用的方式捕获所有的外部自动变量。
[=] 以值的方式捕获所有的外部自动变量。
[] 不捕获外部的任何变量。
*/
[ capture ] ( params ) mutable exception attribute -> returnType { body }

使用例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
std::cout << [](float f) { return std::abs(f); } (-3.5);
std::cout << [](float f) -> int { return std::abs(f); } (-3.5);

//当我们想引用一个 lambda 表达式时,我们可以使用auto关键字
auto lambda = [] () -> int { return val * 100; };
//auto关键字实际会将 lambda表达式转换成一种类似于std::function的内部类型
//(但并不是std::function类型,虽然与std::function“兼容”)。所以,我们也可以这么写:
std::function<int()> lambda = [] () -> int { return val * 100; };

//传值方式,改变capture变量
float f0 = 1.0;
std::cout << [=](float f) mutable { return f0 += std::abs(f); } (-3.5); //f0仍然是1.0

//对于[=]或[&]的形式,lambda 表达式可以直接使用 this 指针。
//但是,对于[]的形式,如果要使用 this 指针,必须显式传入:
[this]() { this->someFunc(); }();