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成员函数。