经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
【C++】C++之Lambda表达式
来源:cnblogs  作者:李春港  时间:2020/12/8 9:14:25  对本文有异议

作者:李春港
出处:https://www.cnblogs.com/lcgbk/p/14088462.html

一、前言

由于前段时间在阅读一些C++源码的时候发现了Lambda表达式,所以在此也记录下Lambda表达式的使用。

很早之前Lambda在很多高级语言中,就已经被广泛地使用了,在一个程序中Lambda表达式可以理解为是匿名函数。在C++中,到了C++11标准才引入了这个Lambda表达式,这是C++11最重要而且也是最常用的特性之一。

使用Lambda表达式,不需要额外地定义函数名,可以更直接编写程序,有比较好的可读性和可维护性;不需要另外声明和定义函数体,避免了程序代码的膨胀。

二、Lambda表达式格式说明

2.1 完整的Lambda表达式格式

  1. [capture list] (params list) mutable exception-> return type { function body }

说明:

名称 解析
[capture list] 捕获列表:lambda 表达式可以通过捕获列表捕获一定范围内的变量。
(params list) 形参列表,用于传参(可以省略)。
mutable 用来说明是否可以修改按值捕获的变量(可以省略),如果需要修改按值捕获的变量,则需要添加。
exception 异常设定(可以省略)。
return type 返回类型 (可省略,如果省略则自动从函数体中判断返回类型,return后的值。如果没有则返回void)。
function body 函数体,即逻辑代码。

2.2 常见的Lambda表达式格式

编号 格式 特性
格式1 [capture list] (params list) -> return type {function body} 1、无法修改捕获列表中的变量值。
格式2 [capture list] (params list) {function body} 1、无法修改捕获列表中的变量值;2、返回类型由return返回的值类型确定,如果没有return语句,则返回类型为void。
格式3 [capture list] {function body} 1、无法修改捕获列表中的变量值;2、返回类型由return返回的值类型确定,如果没有return语句,则返回类型为void;3、不能传入参数,类似普通的无参函数。

2.3 lambda 表达式捕获列表

捕获形式 解析
[ ] 不捕获任何变量。
[&] 捕获外部作用域中所有变量,并作为引用在函数体中使用(按引用捕获)。
[=] 捕获外部作用域中所有变量,并作为副本在函数体中使用(按值捕获)。
[=,&x] 按值捕获外部作用域中所有变量,并按引用捕获 x 变量。
[x] 按值捕获 x 变量,同时不捕获其他变量。
[this] 捕获当前类中的 this 指针,让 lambda 表达式拥有和当前类成员函数同样的访问权限。如果已经使用了 & 或者 =,就默认添加此选项。

注意:

  • 如果是按值捕获,那么是否可以改变捕获的变量值,取决于mutable关键字。

三、示例

3.1 STL的sort函数参数使用Lambda

  1. /*****************************************************************************
  2. ** Copyright ? 2020 lcg. All rights reserved.
  3. ** File name: Lambda.cpp
  4. ** Description: 在STL的sort函数参数使用Lambda表达式
  5. ** Author: lcg
  6. ** Version: 1.0
  7. ** Date: 2020.12.04
  8. *****************************************************************************/
  9. #include <iostream>
  10. #include <vector>
  11. #include <algorithm>
  12. using namespace std;
  13. bool cmp(int a, int b)
  14. {
  15. return a < b;
  16. }
  17. int main()
  18. {
  19. vector<int> vec{ 3, 2, 5, 7, 3, 2 };
  20. vector<int> lbvec(vec);
  21. /**1、不使用Lambda表达式的写法**/
  22. sort(vec.begin(), vec.end(), cmp);
  23. cout << "predicate function:" << endl;
  24. for (int it : vec) // 此for循环写法也是在C++11才出现
  25. cout << it << ' ';
  26. cout << endl;
  27. /**2、使用Lambda表达式的写法**/
  28. sort(lbvec.begin(), lbvec.end(), [](int a, int b) -> bool { return a < b; });
  29. cout << "lambda expression:" << endl;
  30. for (int it : lbvec)
  31. cout << it << ' ';
  32. }

可以看到这种情况使用Lambda表达式可以使代码更加直观、简介,无需再定义 cmp(int a, int b) 函数。

3.2 有返回值的Lambda表达式

  1. /** 1、标明返回类型**/
  2. auto f = [](int a) -> int { return a + 1; };
  3. std::cout << f(1) << std::endl; /**输出: 2**/
  4. /** 2、无标明返回类型**/
  5. auto f = [](int a) { return a + 1; };
  6. std::cout << f(1) << std::endl; /**输出: 2**/

当没有标明返回类型的时候,系统会根据return回来的值来判断返回值的类型,auto会自动检索返回值的类型。

3.3 无参数Lambda表达式

  1. auto f = []() { return 1; };
  2. std::cout << f() << std::endl; /**输出: 1**/

3.4 捕获外部变量的Lambda表达式

  1. /*****************************************************************************
  2. ** Copyright ? 2020 lcg. All rights reserved.
  3. ** File name: Lambda.cpp
  4. ** Description: 捕获外部变量的Lambda表达式
  5. ** Author: lcg
  6. ** Version: 1.0
  7. ** Date: 2020.12.04
  8. *****************************************************************************/
  9. #include <iostream>
  10. class A
  11. {
  12. public:
  13. int i_ = 0;
  14. void func(int x, int y)
  15. {
  16. /* error,没有捕获外部变量*/
  17. auto x1 = []{ return i_; };
  18. /*OK,按值捕获所有外部变量,包括了this指针*/
  19. auto x2 = [=]{ return i_ + x + y; };
  20. /*OK,按引用捕获所有外部变量,包括了this指针*/
  21. auto x3 = [&]{ return i_ + x + y; };
  22. /*OK,捕获this指针,Lambda拥有和此类中普通函数一样的权限*/
  23. auto x4 = [this]{ return i_; };
  24. /*error,没有捕获x、y,因为x、y变量不属于this*/
  25. auto x5 = [this]{ return i_ + x + y; };
  26. /* OK,捕获this指针、x、y*/
  27. auto x6 = [this, x, y]{ return i_ + x + y; };
  28. /*OK,捕获this指针,并修改成员的值*/
  29. auto x7 = [this]{ return i_=7; };
  30. x7();
  31. std::cout<<i_<<std::endl;//输出7
  32. /*OK,捕获所有外部变量,默认捕获this指针,并修改成员的值*/
  33. auto x8 = [=]{ return i_=8; };
  34. x8();
  35. std::cout<<i_<<std::endl;//输出8
  36. /*error,因为i_不属于捕获范围的变量,所以无法按值捕获i_变量,可以通过捕获this指针来获取i_使用权*/
  37. auto x9 = [i_]{ return i_++; };
  38. /*error,原因同上*/
  39. auto x10 = [&i_]{ return i_++; };
  40. /*ok,按引用捕获所有变量,默认捕获this指针,并修改成员的值*/
  41. auto x11 = [&]{ return i_=11; };
  42. x11();
  43. std::cout<<i_<<std::endl;//输出11
  44. /*error,按值捕获x变量,并修改值*/
  45. auto x12 = [x]{ return x++; };
  46. /*ok,按值捕获x变量,并修改值*/
  47. auto x13 = [x]()mutable{ return x=13; };
  48. x13();
  49. std::cout<<x<<std::endl;//输出1
  50. /*ok,按引用捕获x变量,并修改值*/
  51. auto x14 = [&x]{ return x=14; };
  52. x14();
  53. std::cout<<x<<std::endl;//输出14
  54. }
  55. };
  56. int main(int argc, char *argv[])
  57. {
  58. A l;
  59. l.func(1,2);
  60. int a = 0, b = 1;
  61. /*error,没有捕获外部变量*/
  62. auto f1 = []{ return a; };
  63. /*OK,捕获所有外部变量,改变a值*/
  64. auto f2 = [&]{ return a=2; };
  65. f2();
  66. std::cout<<a<<std::endl;//输出2
  67. /*OK,捕获所有外部变量,并返回a*/
  68. auto f3 = [=]{ return a; };
  69. /*error,a是以复制方式捕获的,无法修改*/
  70. auto f4 = [=]{ return a=4; };
  71. /*ok,a是以复制方式捕获的,修改a值*/
  72. auto f4 = [=]()mutable{ return a=4; };
  73. f4();
  74. std::cout<<a<<std::endl;//输出2
  75. /*error,没有捕获变量b*/
  76. auto f5 = [a]{ return a + b; };
  77. /*OK,捕获a和b的引用,并对b做自加运算*/
  78. auto f6 = [a, &b]{ return a + (b++); };
  79. /*OK,捕获所有外部变量和b的引用,并对b做自加运算*/
  80. auto f7 = [=, &b]{ return a + (b++); };
  81. return 0;
  82. }

总结:

  • 当按值的方式获取外部变量时,是无法更改获取过来的值的,除非使用mutable关键字声明,就可以更改(更改的不是外部变量原本地址里的值,而是lambda函数体内的副本);
  • 当按引用的方式捕获外部变量时,lambda函数体内可以更改此值,更改的是外部变量原本地址里的值;
  • 当在类中,lambda表达式捕获this指针时,lambda函数体内可以直接改变该类中的变量,和类中的普通函数拥有一样的权限。

原文链接:http://www.cnblogs.com/lcgbk/p/14088462.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号