有关Lambda语法
参见此处
实现原理
1 | void LambdaTest() |
编译器实现时大概分为如下步骤
- 创建对于的 lambda 类,捕获的值为类内成员变量,重载 operator();
- 创建 lambda 对象;
- 通过对象调用 operator()。
1 | class lambda_xxxx |
解析
- lambda 表达式捕获列表对应类中 private 成员;
- lambda 表达式形参对应类中 operator() 的形参;
- lambda 表达式中mutable关键词对应 operator() 的 const 修饰;
- lambda 表达式中的返回类型对应 operator() 的返回类型;
- lambda 表达式中函数体对应类中 operator() 的函数体。
- 且当 lambda 表达式捕获方式不同,也会影响类中 private 成员的类型:
- 当使用**值捕获(=)**,private 成员的类型与捕获变量类型一致;
- 当使用**引用捕获(&)**,private 成员的类型也是捕获变量的引用类型。
- 类名 lambda_xxxx 的 xxxx 是为了防止命名冲突加上的。
特殊情况
转自链滴
当 lambda 表达式不捕获任何外部变量时,特定情况下会有额外的代码产生。
其中,特定情况是指:有 lambda_xxxx 类 到 函数指针 的类型转换
如以下代码
1 | typedef int(_stdcall *Func)(int); |
- Test 函数接受一个函数指针作为参数,并调用这个函数指针。
- 实际调用 Test 时,传入的参数却是一个 Lambda 表达式,所以这里有一个类型的隐式转换
lambda_xxxx -> 函数指针。
上面已经提到,Lambda 表达式就是一个 lambda_xxxx 类的匿名对象,与函数指针之间按理说不应该存在转换,但是上述代码却没有问题。
其问题关键在于,上述代码中,lambda 表达式没有捕获任何外部变量,即 lambda_xxxx 类没有任何成员变量,在 operator() 中也就不会用到任何成员变量,也就是说,operator() 虽然是个成员函数,它却不依赖 this 就可以调用。
因为不依赖 this,所以 一个 lambda_xxxx 类的匿名对象与函数指针之间就存在转换的可能。
大致过程如下:
- 在 lambda_xxxx 类中生成一个静态函数,静态函数的函数签名与 operator() 一致,**在这个静态函数中,通过一个空指针去调用该类的 operator()**;
- 在 lambda_xxxx 重载与函数指针的类型转换操作符,在这个函数中,返回第 1 步中静态函数的地址。
1 | typedef int(_stdcall *Func)(int); |
上述代码只是以 __stdcall 调用约定的函数指针举例,实际使用时,对于不同调用约定,会生成对应版本的静态函数和类型转换函数。