随笔-91  评论-137  文章-0  trackbacks-0

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 阅读(2662) 评论(0)  编辑 收藏 引用 所属分类: 其他

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理