lambda表达式在C++11中引入,用lambda表达式表示匿名函数非常方便,语法很简单,而且可以使代码更紧凑,更易于阅读。 一个例子:
auto f{ []{ cout << "Hello \n"; } };
f();
或者
int a = 10;
cout << [a](int base)-> int{
for(int i=0;i<a;i++){
base += i;
}
returm base;
}(0) << endl;
声明一个lambda表达式的基本语法为: [函数对象参数] (函数参数) mutable 或 exception 声明 -> 返回值类型 {函数体}
那这个lambda表达式是如何实现的呢? 编译器会针对lambda表达式生成一个匿名类,然后根据lambda表达式捕获的变量构造该匿名类的一个对象,实际调用lambda表示式会调用匿名类对象的operator()方法。 假设我们编写了这样的lambda函数:
int a = 10;
auto f[a](int base)-> int{
for(int i=0;i<a;i++){
base += i;
}
returm base;
};
f(0);
对于这样的代码,编译器可能是生成了如下代码:
class lambda_0s8s5d2 {
public:
lambda_0s8s5d2(int a):a(a){}
int operator()(int base) const {
for(int i=0;i<a;i++){
base += i;
}
returm base;
}
private:
int a;
};
int a = 10;
lambda_0s8s5d2 f(a);
f(0);
这里的匿名类名字是随便取的,看gdb里面匿名类的命名实现比较复杂。
也是说每一个lambda表达式都是一个函数对象,是仿函数,不是C中普通函数。因为它是对象,所以可以捕获变量,通过值传递或者引用传递。
所以看lambda表达式语法的五个部分分别对应什么样的实现:
- [函数对象参数]。当使用[x]时,在匿名类中添加一个x所属类型的值。当使用[&y],在匿名类中添加一个y所属类型的引用。当使用[=]时,将函数体内用到的所有外部变量的值都声明一个到匿名类中。当使用[&]时,将函数体内用到的所有外部变量的引用都声明一个到匿名类中。当使用[this]时,添加一个this所属类型的指针。
- 函数参数。即匿名类operator方法的函数参数。
- mutable 或 exception 声明。如果默认省略mutable声明,则代表operator()方法为const类型,即不能修改匿名类的成员变量,即不能修改被捕获的值。如果添加了mutable声明,则修改匿名类的成员变量,但如果捕获变量是值传递的,不会修改外部变量,如果捕获引用,则可以修改外部变量。 exception 声明是为匿名类的operator()方法添加异常声明。
- 返回值类型。如果省略,匿名类的operator()方法也可以用auto类型(能够推断出来。
- 函数体。匿名类的operator()方法的函数体。
|