Lambda表達式提供了匿名函數這個概念,可以使您在一個函數中書寫另一個匿名的函數體
先來看下如何在VC2010中書寫Lambda表達式
[捕捉項表](參數表)->返回類型{函數體}
捕捉項表中在變量前添加&操作符表示捕捉引用,添加=表示捕捉值
參數表與"->"和后面的返回類型是可選的編譯器會由函數體內的return語句判斷返回類型,當返回類型很復雜時編譯器無法判斷,則必須手動給出!
下面舉個簡單的例子:
1 #include <stdio.h>
2
3 int main()
4 {
5 int a = 100;
6 [a]{
7 printf("%d\n",a);
8 }();
9 return 0;
10 }
然后在VS2010提示中編譯它:cl /FAs a.cpp
/FAs參數指定了輸出匯編文件a.asm.
然后我們來看一下它生成的匯編代碼:
1 ; Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01
2
3 TITLE D:\a.cpp
4 .686P
5 .XMM
6 include listing.inc
7 .model flat
8
9 INCLUDELIB LIBCMT
10 INCLUDELIB OLDNAMES
11
12 PUBLIC ??R<lambda0>@?A0x428ab923@@QBEXXZ ; `anonymous namespace'::<lambda0>::operator()
13 PUBLIC ??0<lambda0>@?A0x428ab923@@QAE@ABH@Z ; `anonymous namespace'::<lambda0>::<lambda0>
14 PUBLIC _main
15 ; Function compile flags: /Odtp
16 ; File d:\a.cpp
17 _TEXT SEGMENT
18 $T3875 = -8 ; size = 4
19 _a$ = -4 ; size = 4
20 _main PROC
21
22 ; 4 : {
23
24 push ebp
25 mov ebp, esp
26 sub esp, 8
27
28 ; 5 : int a = 100;
29
30 mov DWORD PTR _a$[ebp], 100 ; 00000064H
31
32 ; 6 : [a]{
33 ; 7 : printf("%d\n",a);
34 ; 8 : }();
35
36 lea eax, DWORD PTR _a$[ebp]
37 push eax
38 lea ecx, DWORD PTR $T3875[ebp]
39 call ??0<lambda0>@?A0x428ab923@@QAE@ABH@Z ; `anonymous namespace'::<lambda0>::<lambda0>
40 mov ecx, eax
41 call ??R<lambda0>@?A0x428ab923@@QBEXXZ ; `anonymous namespace'::<lambda0>::operator()
42
43 ; 9 : return 0;
44
45 xor eax, eax
46
47 ; 10 : }
48
49 mov esp, ebp
50 pop ebp
51 ret 0
52 _main ENDP
53 ; Function compile flags: /Odtp
54 _TEXT ENDS
55 ; COMDAT ??0<lambda0>@?A0x428ab923@@QAE@ABH@Z
56 _TEXT SEGMENT
57 _this$ = -4 ; size = 4
58 __A$ = 8 ; size = 4
59 ??0<lambda0>@?A0x428ab923@@QAE@ABH@Z PROC ; `anonymous namespace'::<lambda0>::<lambda0>, COMDAT
60 ; _this$ = ecx
61
62 ; 8 : }();
63
64 push ebp
65 mov ebp, esp
66 push ecx
67 mov DWORD PTR _this$[ebp], ecx
68 mov eax, DWORD PTR _this$[ebp]
69 mov ecx, DWORD PTR __A$[ebp]
70 mov edx, DWORD PTR [ecx]
71 mov DWORD PTR [eax], edx
72 mov eax, DWORD PTR _this$[ebp]
73 mov esp, ebp
74 pop ebp
75 ret 4
76 ??0<lambda0>@?A0x428ab923@@QAE@ABH@Z ENDP ; `anonymous namespace'::<lambda0>::<lambda0>
77 _TEXT ENDS
78 PUBLIC ??_C@_03PMGGPEJJ@?$CFd?6?$AA@ ; `string'
79 EXTRN _printf:PROC
80 ; COMDAT ??_C@_03PMGGPEJJ@?$CFd?6?$AA@
81 CONST SEGMENT
82 ??_C@_03PMGGPEJJ@?$CFd?6?$AA@ DB '%d', 0aH, 00H ; `string'
83 ; Function compile flags: /Odtp
84 CONST ENDS
85 ; COMDAT ??R<lambda0>@?A0x428ab923@@QBEXXZ
86 _TEXT SEGMENT
87 _this$ = -4 ; size = 4
88 ??R<lambda0>@?A0x428ab923@@QBEXXZ PROC ; `anonymous namespace'::<lambda0>::operator(), COMDAT
89 ; _this$ = ecx
90
91 ; 6 : [a]{
92
93 push ebp
94 mov ebp, esp
95 push ecx
96 mov DWORD PTR _this$[ebp], ecx
97
98 ; 7 : printf("%d\n",a);
99
100 mov eax, DWORD PTR _this$[ebp]
101 mov ecx, DWORD PTR [eax]
102 push ecx
103 push OFFSET ??_C@_03PMGGPEJJ@?$CFd?6?$AA@
104 call _printf
105 add esp, 8
106
107 ; 8 : }();
108
109 mov esp, ebp
110 pop ebp
111 ret 0
112 ??R<lambda0>@?A0x428ab923@@QBEXXZ ENDP ; `anonymous namespace'::<lambda0>::operator()
113 _TEXT ENDS
114 END
115
由匯編代碼可以看到先為Lambda函數生成了一個匿名對象,然后調用了()的操作符重載函數調用這個匿名函數.
由此我們得出結論:調用一個匿名函數并沒有調用一個存在的函數或是一個類的成員函數快,只是書寫更方便罷了.
然后我們修改一下代碼,將匿名函數先賦給一個匿名函數指針,然后調用.
1 #include <stdio.h>
2
3 int main()
4 {
5 int a = 100;
6 auto ptr = [a]{
7 printf("%d\n",a);
8 };
9 ptr();
10 return 0;
11 }
編譯后得到代碼:
1 ; Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01
2
3 TITLE D:\a.cpp
4 .686P
5 .XMM
6 include listing.inc
7 .model flat
8
9 INCLUDELIB LIBCMT
10 INCLUDELIB OLDNAMES
11
12 PUBLIC ??R<lambda0>@?A0x428ab923@@QBEXXZ ; `anonymous namespace'::<lambda0>::operator()
13 PUBLIC ??0<lambda0>@?A0x428ab923@@QAE@ABH@Z ; `anonymous namespace'::<lambda0>::<lambda0>
14 PUBLIC _main
15 ; Function compile flags: /Odtp
16 ; File d:\a.cpp
17 _TEXT SEGMENT
18 _ptr$ = -8 ; size = 4
19 _a$ = -4 ; size = 4
20 _main PROC
21
22 ; 4 : {
23
24 push ebp
25 mov ebp, esp
26 sub esp, 8
27
28 ; 5 : int a = 100;
29
30 mov DWORD PTR _a$[ebp], 100 ; 00000064H
31
32 ; 6 : auto ptr = [a]{
33 ; 7 : printf("%d\n",a);
34 ; 8 : };
35
36 lea eax, DWORD PTR _a$[ebp]
37 push eax
38 lea ecx, DWORD PTR _ptr$[ebp]
39 call ??0<lambda0>@?A0x428ab923@@QAE@ABH@Z ; `anonymous namespace'::<lambda0>::<lambda0>
40
41 ; 9 : ptr();
42
43 lea ecx, DWORD PTR _ptr$[ebp]
44 call ??R<lambda0>@?A0x428ab923@@QBEXXZ ; `anonymous namespace'::<lambda0>::operator()
45
46 ; 10 : return 0;
47
48 xor eax, eax
49
50 ; 11 : }
51
52 mov esp, ebp
53 pop ebp
54 ret 0
55 _main ENDP
56 ; Function compile flags: /Odtp
57 _TEXT ENDS
58 ; COMDAT ??0<lambda0>@?A0x428ab923@@QAE@ABH@Z
59 _TEXT SEGMENT
60 _this$ = -4 ; size = 4
61 __A$ = 8 ; size = 4
62 ??0<lambda0>@?A0x428ab923@@QAE@ABH@Z PROC ; `anonymous namespace'::<lambda0>::<lambda0>, COMDAT
63 ; _this$ = ecx
64
65 ; 8 : };
66
67 push ebp
68 mov ebp, esp
69 push ecx
70 mov DWORD PTR _this$[ebp], ecx
71 mov eax, DWORD PTR _this$[ebp]
72 mov ecx, DWORD PTR __A$[ebp]
73 mov edx, DWORD PTR [ecx]
74 mov DWORD PTR [eax], edx
75 mov eax, DWORD PTR _this$[ebp]
76 mov esp, ebp
77 pop ebp
78 ret 4
79 ??0<lambda0>@?A0x428ab923@@QAE@ABH@Z ENDP ; `anonymous namespace'::<lambda0>::<lambda0>
80 _TEXT ENDS
81 PUBLIC ??_C@_03PMGGPEJJ@?$CFd?6?$AA@ ; `string'
82 EXTRN _printf:PROC
83 ; COMDAT ??_C@_03PMGGPEJJ@?$CFd?6?$AA@
84 CONST SEGMENT
85 ??_C@_03PMGGPEJJ@?$CFd?6?$AA@ DB '%d', 0aH, 00H ; `string'
86 ; Function compile flags: /Odtp
87 CONST ENDS
88 ; COMDAT ??R<lambda0>@?A0x428ab923@@QBEXXZ
89 _TEXT SEGMENT
90 _this$ = -4 ; size = 4
91 ??R<lambda0>@?A0x428ab923@@QBEXXZ PROC ; `anonymous namespace'::<lambda0>::operator(), COMDAT
92 ; _this$ = ecx
93
94 ; 6 : auto ptr = [a]{
95
96 push ebp
97 mov ebp, esp
98 push ecx
99 mov DWORD PTR _this$[ebp], ecx
100
101 ; 7 : printf("%d\n",a);
102
103 mov eax, DWORD PTR _this$[ebp]
104 mov ecx, DWORD PTR [eax]
105 push ecx
106 push OFFSET ??_C@_03PMGGPEJJ@?$CFd?6?$AA@
107 call _printf
108 add esp, 8
109
110 ; 8 : };
111
112 mov esp, ebp
113 pop ebp
114 ret 0
115 ??R<lambda0>@?A0x428ab923@@QBEXXZ ENDP ; `anonymous namespace'::<lambda0>::operator()
116 _TEXT ENDS
117 END
118
和上面的直接調用并無差別,因為一個匿名函數含有一個隱藏的對象.
應此__asm call ptr;這樣調用是錯誤的!因為你無法用call指令來調用一個對象的成員函數.
posted on 2011-02-17 16:32
lwch 閱讀(2673)
評論(0) 編輯 收藏 引用 所屬分類:
其他