1. Lamda表达式作用:
    Lambda表达式类似Javascript中的闭包,它可以用于创建并定义匿名的函数对象,以简化编程工作。
  2. Lambda的语法如下:
    [函数对象参数](操作符重载函数参数)->返回值类型{函数体}
vector<int> iv{5, 4, 3, 2, 1};
int a = 2, b = 1;
int foo = 3;for_each(iv.begin(), iv.end(), [b](int &x){cout<<(x + b)<<endl;}); // (1)  for_each(iv.begin(), iv.end(), [=](int &x){x *= (a + b);});     // (2)  for_each(iv.begin(), iv.end(), [=](int &x)->int{return x * (a + b);});// (3)

• []内的参数指的是Lambda表达式可以取得的全局变量。
(1)函数中的b就是指函数可以得到在Lambda表达式外的全局变量,如果在[]中传入=的话,即是可以取得所有的外部变量,如(2)和(3) Lambda表达式
• ()内的参数是每次调用函数时传入的参数。
• ->后加上的是Lambda表达式返回值的类型,如(3)中返回了一个int类型的变量
• 下面是各种变量捕获的选项
o [] 不捕获任何变量
o [&} 捕获外部作用域中所有变量,并作为引用在函数体中使用
o [=] 捕获外部作用域中所有变量,并拷贝一份在函数体中使用
o [=, &b] 捕获外部作用域中所有变量,并拷贝一份在函数体中使用,但是对b变量使用引用
o [b] 捕获b变量并且拷贝一份在函数体使用,同时不捕获其他变量
o [this] 捕获当前类中的this指针。如果已经使用了&或者=就默认添加此选项。
小结: Lamda 表达式主要用于创建匿名的函数对象,简化编码。最重要的就是[函数对象参数] 的使用。对于上面各种变量捕获的选项,需要熟记。
下面给出一些样例:

  • [] 不捕获任何变量
std::vector<int> tempVec{1, 2, 3, 4, 5};
int a = 8;
int b = 2;
for_each(tempVec.begin(), tempVec.end(), [](int& x){cout << x + b << endl;
});

报错:

  error: 'b' is not capturedcout << x + b << endl;^
F:\clion project\main.cpp:67:47: note: the lambda has no capture-defaultfor_each(tempVec.begin(), tempVec.end(), [](int& x){

捕获列表为空,默认不获取任何变量,所以Lamda表达式内部使用 b 会报 未捕获。

  • [&} 捕获外部作用域中所有变量,并作为引用在函数体中使用
std::vector<int> tempVec{1, 2};
int a = 8;
int b = 2;
cout << "a addr:" << &a << endl;
cout << "b addr:" << &b << endl;
for_each(tempVec.begin(), tempVec.end(), [&](int& x){cout << x + b  + a<< endl;cout << "capture a addr: " << &a << endl;cout << "capture b addr: " << &b << endl;
});

输出结果:

a addr:0x61fd8c
b addr:0x61fd88
11
capture a addr: 0x61fd8c
capture b addr: 0x61fd88
12
capture a addr: 0x61fd8c
capture b addr: 0x61fd88

可以看出a, b 的地址在 Lamda表示的外部和内部是相同的,即a, b是作为引用传递到Lamda表达式内部的。

  • [=] 捕获外部作用域中所有变量,并拷贝一份在函数体中使用
std::vector<int> tempVec{1, 2};
int a = 8;
int b = 2;
cout << "a addr:" << &a << endl;
cout << "b addr:" << &b << endl;
for_each(tempVec.begin(), tempVec.end(), [=](int& x){cout << x + b  + a<< endl;cout << "capture a addr: " << &a << endl;cout << "capture b addr: " << &b << endl;
});

输出:

a addr:0x61fdac
b addr:0x61fda8
11
capture a addr: 0x61fd84
capture b addr: 0x61fd80
12
capture a addr: 0x61fd84
capture b addr: 0x61fd80

可以看出Lamda 表达式的内部和外部 使用的是不同地址的a, b变量,说明是拷贝了外部变量传递到表达式内部的。有一个问题: 为什么 内部 连续2次输出的a, b 变量是同一个地址呢? 这个留到后面讲解Lamda表达式的具体实现。可以简单理解为a,b 被复制了一份存储到函数对象内部,作为成员变量。

  • [=, &b] 捕获外部作用域中所有变量,并拷贝一份在函数体中使用,但是对b变量使用引用
std::vector<int> tempVec{1, 2};
int a = 8;
int b = 2;
cout << "a addr:" << &a << endl;
cout << "b addr:" << &b << endl;
for_each(tempVec.begin(), tempVec.end(), [=, &b](int& x){cout << x + b  + a<< endl;cout << "capture b addr: " << &b << endl;cout << "capture a addr: " << &a << endl;
});

输出:

a addr:0x61fd8c
b addr:0x61fd88
11
capture b addr: 0x61fd88
capture a addr: 0x61fd20
12
capture b addr: 0x61fd88
capture a addr: 0x61fd20

可以看出b的地址在 Lamda表示的外部和内部是相同的,但是a 的是不同的,说明a 是拷贝了一份,b 是传递的引用。

  • [b] 捕获b变量并且拷贝一份在函数体使用,同时不捕获其他变量
void Test() {int a = 8;int b = 10;auto func = [b]{cout << a << endl;cout << b << endl;};func();
}

输出:

In lambda function:
F:\clion project\main.cpp:83:17: error: 'a' is not capturedcout << a << endl;^

编译报错,因为捕获列表只有b, 没有a。 只捕获显示说明需要捕获的变量。
删除对a的引用后的代码和输出:

void Test() {int a = 8;int b = 10;cout << &b << endl;auto func = [b]{cout << b << endl;cout << &b << endl;};func();
}

输出:

0x61fde4
10
0x61fde0

可以看到Lamda表达式内部和外部的b 地址不同,说明b 被拷贝了一份到 内部。

  • [this] 捕获当前类中的this指针。如果已经使用了&或者=就默认添加此选项
class Test
{public:void hello() {cout << "test hello" << endl;};void lambda() {auto func = [&]{ // 捕获了 this 指针this->hello(); // 这里 this 调用的就是 class test 的对象了cout << "private param of object:" << this->a << endl;};func();}private:int a{10};
};

输出:

test hello
private param of object:10

捕获列表是&, 默认捕获了this 指针;捕获列表是 = , 输出结果跟上面相同。说明this 指针也被默认捕获。

再说明几个特殊的场景:

  • 捕获变量定义在表达式之后
int main()
{auto func = [=]{cout << a << endl;};func();int a = 10;return 0;
}

输出:

F:\clion project\main.cpp:82:17: error: 'a' was not declared in this scopecout << a << endl;^

通过上面的例子,说明Lamda表达式只能捕获在自身定义之前的变量。

  • 捕获的变量在表达式之后有操作
int main()
{int a = 10;int b = 5;auto func = [=, &b]{cout << "a is:" << a << endl;cout << "b is:" << b << endl;};a = 20;b = 8;func();return 0;
}

输出:

a is:10
b is:8

b作为引用,变化影响了表达式的输出;但是a 作为拷贝,输出的仍然是表达式定义前的值。这个原因是什么?下面的部分会讲解。

  • 捕获静态变量
int main()
{static int c = 6;auto func = [c]{cout << "c is:" << c << endl;};c = 8;func();return 0;
}

输出:

warning: capture of variable 'c' with non-automatic storage durationauto func = [c]{^
c is:8

静态变量出现在捕获列表中会出现告警,同时 它也不符合 捕获列表的行为(c会拷贝一份到内部,同时不受外部影响),c 在外部被操作,仍然影响了表达式的输出。
-3. Lambda表达式的内部实现
当编写一个lambda表达式之后,编译器将该表达式翻译成一个未命名类的未命名对象。
所以上面说的拷贝 实际是在这个表达式定义的未命名类中添加了成员变量,并在表达式翻译成对象时完成初始化;所以地址和 值 在 表达式定义的地方确定,外部的其他操作不会再影响它,同时它的地址在循环中调用时总是不变。
对于引用捕获,编译器则直接使用该变量,所以需要程序自身保证引用时外部变量是有效的。
捕获列表只用于局部非static变量,lambda表达式可以直接使用局部static变量和它所在函数之外声明的名字;所以上面的例子中捕获了静态变量会告警,同时外部的修改也会影响表达式的输出。

参考博客: https://www.jianshu.com/p/81bc3fd67d4a 写的很好,推荐阅读。

C++ Lamda表达式相关推荐

  1. 委托、lamda表达式..委托概念-匿名函数-泛型委托-Lamda表达式-多播委托

    委托 一.什么是委托? 将一个方法作为参数传递给另一个方法(参数类型为委托delegate).   声明一个委托类型. 委托所指向的函数必须跟委托具有相同的的签名(参数个数.参数类型.返回值一样). ...

  2. 为了去重复,写了一个通用的比较容器类,可以用在需要比较的地方,且支持Lamda表达式...

    为了去重复,写了一个通用的比较容器类,可以用在需要比较的地方,且支持Lamda表达式,代码如下: public class DataComparer<T>:IEqualityCompare ...

  3. Java --Lamda表达式

    Lamda:属于函数式编程的概念: interface IMessage {public void print() ; } public class TestDemo {public static v ...

  4. 什么是lamda表达式?

    我们首先来看一下这一片代码: 1 class Solution { 2 public: 3 int singleNumber(int A[], int n) { 4 // Note: The Solu ...

  5. [.net 面向对象程序设计进阶] (7) Lamda表达式(三) 表达式树高级应用

    [.net 面向对象程序设计进阶] (7) Lamda表达式(三) 表达式树高级应用 本节导读:讨论了表达式树的定义和解析之后,我们知道了表达式树就是并非可执行代码,而是将表达式对象化后的数据结构.是 ...

  6. 带参的信号、lamda表达式及坐标系统

    带参的信号.lamda表达式及坐标系统 文章目录 带参的信号.lamda表达式及坐标系统 一.带参的信号 二.lamda表达式 三.坐标系统 一.带参的信号 1. 自定义信号(这个信号不像标准信号是一 ...

  7. 静态内部类、局部内部类、匿名内部类、lamda表达式

    普通的继承: 静态内部类( 必须有static修饰): 局部内部内(写在任意方法中的): 匿名内部类(可以写在任意位置): lamda表达式(感觉像匿名内部类的简化)(前题是函数式接口:接口中只有一个 ...

  8. 一个小案例精通lamda表达式与函数式接口

    前言:只有基础(多态.匿名接口实现类)足够扎实才能更好的学习花拳绣腿(lamda表达式),Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性.Lambda 允许把函数作为一 ...

  9. c++ lamda表达式调用自身实现定时器

    刚好要做一个定时器,用asio的deadline_timer,通过异步等待方式去做,超时后重新设置超时时间再重新异步等待. 将lamda表达式放到function中,异步等待的时候再调用自身. 具体代 ...

  10. [ASP.NET MVC]让Html.RenderAction支持Lamda表达式

    今天在ASP.NET MVC代码时用到了Html.RenderAction,代码如下: @{Html.RenderAction("RecentNews")} 通过字符串指定Acti ...

最新文章

  1. Python如何实现单步调试
  2. 【转载】进程间的通信之剪贴板方法实现源码
  3. linux扩充单个路径下的内存,超详尽!Linux云服务器存储扩容实操
  4. 基于智能计算的降维技术研究与应用
  5. HashMap深度解析:一文让你彻底了解HashMap
  6. display 隐藏css,CSS-元素的显示与隐藏
  7. 新建test.c为什么没有.h文件_新建STM32工程全局声明两个宏的原因
  8. 锁定计算机的软件,易通电脑锁(控制上网时间必备软件)
  9. 鼠标右键中没有新建选项,解决方法!
  10. Windows Phone 7 日历应用的实现
  11. R语言-混合型数据聚类
  12. github pages + Hexo + 域名绑定搭建个人博客增强版
  13. 关于EasyDarwinGo部署海康威视rtsp转hls视频多摄像头的服务器视频转码
  14. 毕业设计-基于 MATLAB 的图像分割算法研究及实现
  15. 给定一个完全循环赛的比赛结果,其中n个队伍两两比赛一次。每场比赛以一方胜出或者平局结束。设计一个算法,把n个队伍排序,序列中每个队伍都不曾输给紧随其后的那个队伍。说明该算法的时间效率类型。
  16. 微信小程序---霍兰德职业兴趣测试、心里测评、性格测评
  17. Android用Double Array Trie (双数组)实现关键字的搜索
  18. tekton TriggerTemplate资源
  19. 3星|《混乱》:案例比较有趣,推导过程和结论略牵强
  20. learnopengl 中 pbr的球体算法

热门文章

  1. iPhone手机通讯录如何导入另一部手机?
  2. 肯德基快餐店的收银系统
  3. ros 设置 catkin_make -j -l
  4. 两个助你高效编写 Kubernetes YAML 文件的神技
  5. c语言实验设计报告,c语言实验设计报告计科学号.doc
  6. 美团面试官:生成订单后一段时间不支付订单会自动关闭的功能该如何实现?越详细越好~
  7. Linux 查看进程、杀死进程
  8. html九宫格挖正方形代码,使用css伪类before/after实现 正方形三宫格、正方形六宫格、正方形九宫格...
  9. 苹果原装笔与其他触控笔有啥区别?Ipad好用触控笔推荐
  10. Vim 快捷键速查表