C++11 之 lambda函数的详细使用

桃扇骨 2023-07-18 12:59 103阅读 0赞

1. lambda 函数概述

lambda 表达式是一种匿名函数,即没有函数名的函数;该匿名函数是由数学中的λ演算而来的。通常情况下,lambda函数的语法定义为:

[capture] (parameters) mutable ->return-type {statement}

其中:
[capture] :捕捉列表。捕捉列表总是作为lambda的开始,即出现于lambda的开始处。它是lambda的引出符(即开始标志)。编译器可以根据该“标志”来作出判断出该函数是否为lambda函数。同时“捕捉列表”能够捕捉上下文中的变量以作为lambda函数使用。
(parameters):参数列表。和C/C++中的普通函数参数意义一样。该部分是可选的,意味着如果我们不需要进行参数传递时,可以连同括号“()”一起省略掉。
mutable:该关键字为一个修饰符。在默认的情况下,lambda函数总是返回一个const,而当我们在参数列表后面注明了“mutable”关键字之后,则可以取消其常量性质。若在lambda中使用了mutable修饰符,则“参数列表”是不可省略掉的(即使是参数为空)。
->return-type: 函数的返回值类型。和C/C++中的普通函数返回值类型的性质一样。主要目的是用来追踪lambda函数(有返回值情况下)的返回类型。若lambda函数不需要返回值,则可以直接将这部分省略掉。
{statement}:函数体。在该函数体中,除了可以使用参数列表中的变量外,还可以使用所有捕获到的变量(即[capture] 中的变量)。

见下图:

1.1. lambda 函数中“捕捉列表”详解" class="reference-link">70 1.1. lambda 函数中“捕捉列表”详解

C++11中的lambda函数,其中的“捕捉列表”是由0个或多个“捕捉项”组成,并以逗号“,”分隔。捕捉列表有如下几种形式:

(1)[var] 表示值传递方式捕捉变量var。

  1. #include <iostream>
  2. #include <string>
  3. #include <stdio.h>
  4. using namespace std;
  5. int main()
  6. {
  7. int a = 1,b =2, c =3;
  8. auto retVal = [=,&a,&b]()
  9. {
  10. printf("inner c[%d]\n",c);
  11. a = 10;
  12. b = 20;
  13. return a+b;
  14. };
  15. printf("sum[%d]\n",retVal());
  16. printf("a[%d] b[%d] c[%d]\n",a,b,c);
  17. return 0;
  18. }

打印结果:
inner c[3]
sum[30]
a[10] b[20] c[3]

上面的代码中,“捕捉列表”由3项组成。以引用传递的方式捕捉变量a、b,以值传递的方式捕捉变量c。因此在lambda表达式的函数体中修改了变量a和b之后,父作用域中的a、b值也改变。而即使是在lambda函数内部修改了变量c的值,父作用域中的c仍然不会受到影响,因为是值传递的方式。(需在参数列表后面加上 mutable 关键字(修饰符))。同时

  1. #include <iostream>
  2. #include <string>
  3. #include <stdio.h>
  4. using namespace std;
  5. int main()
  6. {
  7. int a = 1,b =2, c =3;
  8. auto retVal = [=,&a,&b]() mutable->int
  9. {
  10. printf("inner c[%d]\n",c);
  11. a = 10;
  12. b = 20;
  13. c = 30;
  14. printf("inner c2[%d]\n",c);
  15. return a+b;
  16. };
  17. printf("sum[%d]\n",retVal());
  18. printf("a[%d] b[%d] c[%d]\n",a,b,c);
  19. return 0;
  20. }

打印结果:
inner c[3]
inner c2[30]
sum[30]
a[10] b[20] c[3]

(2)[=] 表示值传递方式捕捉所有父作用域的变量(包括this)。
(3)[&var] 表示引用传递捕捉变量var。
(4)[&] 表示引用传递捕捉所有父作用域的比哪里(2020-02-18 09:36:12 修改) 的变量(包括this)。

  1. #include <iostream>
  2. #include <string>
  3. #include <stdio.h>
  4. using namespace std;
  5. int main()
  6. {
  7. int a = 1,b =2, c =3;
  8. auto retVal = [&]() mutable->int
  9. {
  10. printf("inner a[%d] b[%d] c[%d]\n",a,b,c);
  11. a = 10;
  12. b = 20;
  13. c = 30;
  14. return a+b;
  15. };
  16. printf("sum[%d]\n",retVal());
  17. printf("a[%d] b[%d] c[%d]\n",a,b,c);
  18. return 0;
  19. }

打印结果:
inner a[1] b[2] c[3]
sum[30]
a[10] b[20] c[30]

(5)[this] 表示值传递方式捕捉当前的this指针。
同理(2),(3),(5)可以参考上面的两个例子。

2. lambda 函数特点

(1)在C++11中,lambda函数是inline(内联函数)。

3. lambda 函数使用

代码一

  1. #include <iostream>
  2. #include <string>
  3. #include <stdio.h>
  4. using namespace std;
  5. int main()
  6. {
  7. int a = 6;
  8. int b = 8;
  9. auto sum = [](int a,int b) ->int{return a + b;};
  10. printf("sum[%d]\n",sum(a,b));
  11. return 0;
  12. }

//打印结果:sum[14]

在代码一中,定义了一个简单的lambda函数,该函数的函数列表能够接收两个int类型的数据,而且返回值为int类型。

注意:lambda函数中,参数列表和返回类型都是可选的部分,而且捕捉列表和函数也可以为空。因此,在某种情况下,C++11中的简略版本的lambda函数可以是这样的:

// 完整语法
[ capture-list ] ( params ) mutable(optional) constexpr(optional)(c++17) exception attribute -> ret { body }

// 可选的简化语法
[ capture-list ] ( params ) -> ret { body }
[ capture-list ] ( params ) { body }

最为简洁的版本如下

[ capture-list ] { body }

测试代码二

  1. #include <iostream>
  2. #include <string>
  3. #include <stdio.h>
  4. #include <functional>
  5. using namespace std;
  6. //lambda 表达式的第一种用法
  7. void LambdaUseOne()
  8. {
  9. int a = 1, b = 2, c = 3;
  10. auto retVal = [=, &a, &b]()
  11. {
  12. printf("inner c[%d]\n", c);
  13. a = 10;
  14. b = 20;
  15. return a + b;
  16. };
  17. printf("sum[%d]\n", retVal()); //类似于函数对象的调用
  18. printf("a[%d] b[%d] c[%d]\n", a, b, c);
  19. }
  20. //lambda 表达式的第二种用法
  21. void LambadaUseTwo(int a,std::function<int __stdcall(const int&)> one)
  22. {
  23. int result = one(a); //通过函数参数传入lambda表达式(function类型)
  24. cout << result << endl;
  25. }
  26. //lambda 表达式的第三种用法
  27. void LambdaUseThree()
  28. {
  29. int a = 1, b = 2, c = 3;
  30. [=, &a, &b]()
  31. {
  32. printf("inner c[%d]\n", c);
  33. a = 10;
  34. b = 20;
  35. return a + b;
  36. }(); //直接在函数题后添加括号() 表示直接调用
  37. }
  38. int main()
  39. {
  40. //lambda 表达式的第一种用法
  41. LambdaUseOne();
  42. cout << endl;
  43. //lambda 表达式的第二种用法
  44. int b = 3;
  45. LambadaUseTwo(2, [=](int a)->int
  46. {
  47. return a + b;
  48. }
  49. );
  50. //lambda 表达式的第三种用法
  51. LambdaUseThree();
  52. system("pause");
  53. return 0;
  54. }

发表评论

表情:
评论列表 (有 0 条评论,103人围观)

还没有评论,来说两句吧...

相关阅读

    相关 C++11特性--Lambda函数

    1.Lambda函数 \对于接受函数指针或函数符的函数,可以用匿名定义(lambda)作为其参数。 \仅当Lambda表达式完全由一条返回语句组成时,自动类型推断才管