C++11引入了lambda(匿名函数),这样就可以在一个函数只需调用一次的地方使用了,类似内联函数。
C++11 的 lambda 表达式规范如下:
[ capture ] ( params ) mutable exception attribute -> ret { body } |
(1) | |
[ capture ] ( params ) -> ret { body } |
(2) | |
[ capture ] ( params ) { body } |
(3) | |
[ capture ] { body } |
(4) | |
其中
- (1) 是完整的 lambda 表达式形式,
- (2) const 类型的 lambda 表达式,该类型的表达式不能改捕获("capture")列表中的值。
- (3)省略了返回值类型的 lambda 表达式,但是该 lambda 表达式的返回类型可以按照下列规则推演出来:
- 如果 lambda 代码块中包含了 return 语句,则该 lambda 表达式的返回类型由 return 语句的返回类型确定。
- 如果没有 return 语句,则类似 void f(...) 函数。
- 省略了参数列表,类似于无参函数 f()。
mutable 修饰符说明 lambda 表达式体内的代码可以修改被捕获的变量,并且可以访问被捕获对象的 non-const 方法。
exception 说明 lambda 表达式是否抛出异常(noexcept
),以及抛出何种异常,类似于void f() throw(X, Y)。
attribute 用来声明属性。
另外,capture 指定了在可见域范围内 lambda 表达式的代码内可见得外部变量的列表,具体解释如下:
[a,&b]
a变量以值的方式呗捕获,b以引用的方式被捕获。[this]
以值的方式捕获 this 指针。[&]
以引用的方式捕获所有的外部自动变量。[=]
以值的方式捕获所有的外部自动变量。[]
不捕获外部的任何变量。
此外,params 指定 lambda 表达式的参数。
举个例子:
#include <iostream> using namespace std; int main() { int id = 83; auto e = [id](){ static int count = 1; cout << "id_e"<<count++<<":" << id << endl; //++id; //id为传值方式传入,无权修改id的值 }; auto f = [id]()mutable{ static int count = 1; cout << "id_f"<< count++ << ":" << id << endl; ++id; //id为传值的方式传入,可以修改id的值,但是该id只作为该匿名函数的私有对象,不是外部捕获变量 }; auto g = [&id](){ static int count = 1; cout << "id_g" << count++ << ":" << id << endl; ++id; //id为传引用的方式,函数可以任意修改外部捕获的值,因为此id和外部id是相同变量(具有相同地址) }; auto h = [&id]()mutable{ static int count = 1; cout << "id_h" << count++ << ":" << id << endl; ++id; //同函数g }; id = 42; e(); f(); f(); g(); h(); id = 89; e(); f(); g(); h(); cout << "final id=" << id << endl; return 0; }
运行结果:
可以看到函数e中的id一直没有变化,都是初始值83。注意:捕获值是捕获函数声明前最近的变量的值,即所有以匿名函数捕获的都是最开始的id,但是由于对id的传入方式不一样导致结果不一样!
函数f的值是根据初始的83变化的,并不跟随外部id的改变而改变。
函数g和函数h则是根据外部id值的变化进行改变。
综上所述可以将上述lambda的行为视为一个函数对象(类),如下:
class { public: void operator()(){ cout << "id:" << id << endl; ++id; //OK } private: int id; //copy of outside id };
注意前面的函数e相当于将id设为const对象,因此不能更改id值,或者相当于operator()被定义为一个const成员函数。