基本形式
lambda表达式的本质就是重载了()运算符的类,这种类通常被称为functor,即行为像函数的类。因此lambda表达式对象其实就是一个匿名的functor。
一个标准的lambda表达式包括:捕获列表、参数列表、mutable指示符、尾置返回类型(->返回类型)和函数体:
1
| [capture list] (params list) mutable exception-> return type { function body }
|
- capture list:捕获外部变量列表
- params list:形参列表
- mutable指示符:用来说用是否可以修改捕获的变量
- exception:异常设定
- return type:返回类型
- function body:函数体
用法
lambda实际上是一个匿名仿函数对象。重载operator()来实现仿函数功能。基本使用方法如下:
1 2 3 4 5 6 7 8 9
| int main(){ int x = 9; int y = 19; auto fun = [&x,y](int x, int y){ return x + y; }; fun(x,y); return 0; }
|
反汇编之后可以看到:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| (gdb) disas main Dump of assembler code for function main(): 0x0000000000401569 <+0>: push rbp 0x000000000040156a <+1>: mov rbp,rsp 0x000000000040156d <+4>: sub rsp,0x40 0x0000000000401571 <+8>: call 0x4016f0 <__main> 0x0000000000401576 <+13>: mov DWORD PTR [rbp-0x8],0x9 0x000000000040157d <+20>: mov DWORD PTR [rbp-0x4],0x13 0x0000000000401584 <+27>: lea rax,[rbp-0x8] 0x0000000000401588 <+31>: mov QWORD PTR [rbp-0x20],rax 0x000000000040158c <+35>: mov eax,DWORD PTR [rbp-0x4] 0x000000000040158f <+38>: mov DWORD PTR [rbp-0x18],eax 0x0000000000401592 <+41>: mov edx,DWORD PTR [rbp-0x8] 0x0000000000401595 <+44>: mov ecx,DWORD PTR [rbp-0x4] 0x0000000000401598 <+47>: lea rax,[rbp-0x20] 0x000000000040159c <+51>: mov r8d,ecx 0x000000000040159f <+54>: mov rcx,rax 0x00000000004015a2 <+57>: call 0x401550 <<lambda(int, int)>::operator()(int, int) const> => 0x00000000004015a7 <+62>: mov eax,0x0 0x00000000004015ac <+67>: add rsp,0x40 0x00000000004015b0 <+71>: pop rbp 0x00000000004015b1 <+72>: ret End of assembler dump
|
看到call的是一个lambda(int,int)::operator()(int,int)const方法。
这个函数的反汇编结果是:
1 2 3 4 5 6 7 8 9 10 11 12
| (gdb) disas 0x401550 Dump of assembler code for function <lambda(int, int)>::operator()(int, int) const: 0x0000000000401550 <+0>: push rbp 0x0000000000401551 <+1>: mov rbp,rsp 0x0000000000401554 <+4>: mov QWORD PTR [rbp+0x10],rcx 0x0000000000401558 <+8>: mov DWORD PTR [rbp+0x18],edx 0x000000000040155b <+11>: mov DWORD PTR [rbp+0x20],r8d 0x000000000040155f <+15>: mov edx,DWORD PTR [rbp+0x18] 0x0000000000401562 <+18>: mov eax,DWORD PTR [rbp+0x20] 0x0000000000401565 <+21>: add eax,edx 0x0000000000401567 <+23>: pop rbp 0x0000000000401568 <+24>: ret
|
捕获形式
捕获形式 |
说明 |
[] |
不捕获任何外部变量 |
[变量名, …] |
默认以值得形式捕获指定的多个外部变量(用逗号分隔),如果引用捕获,需要显示声明(使用&说明符) |
[this] |
以值的形式捕获this指针 |
[=] |
以值的形式捕获所有外部变量 |
[&] |
以引用形式捕获所有外部变量 |
[=, &x] |
变量x以引用形式捕获,其余变量以传值形式捕获 |
[&, x] |
变量x以值的形式捕获,其余变量以引用形式捕获 |
需要注意的事项:
- 外部变量是在lambda匿名类构造时传入的。并且传入的是外部变量的引用(由于C++的引用本身就是语法糖,反汇编层面看到的是指针,但是结合源码分析不难得出这里应该是引用)。ambda匿名类会将捕获参数中的变量添加到其成员变量中,并设置一个带有该参数引用类型的构造函数,并在构造函数中完成对相应成员变量的赋值。在调用其operator()函数时,如果用到了捕获列表中的局部变量,则从给匿名类对象的成员变量中取出。