1. 为什么要有lambda表达式存在?
以商品举例,可以通过名字 排序,可以通过价格排序,可以通过评价排序
在C 中,使用仿函数可以进行 价格的比较 若不看仿函数具体实现,则无法通过仿函数对象 来知道 该仿函数到底是怎么比较的 所以就提出了lambda表达式
2. lambda表达式的基本语法
1.[capture-list] :捕捉列表
该列表出现在lambda的开始位置 捕捉列表可以捕捉上下文变量供 lambda函数使用 不可省略,若不进行任何捕捉,则写成 []
2.(paraments) :参数列表
与函数的参数列表相同 若没有参数,可以将()省略
3.mutable:异变
(后面会详细说)
4.-> return- type :返回值类型
可省略,编译器会对返回类型进行推导
5.{statement} :函数体
在函数体内部,除了使用其参数外,还可用捕捉的变量
基本使用
捕捉列表:不可省略,若不进行任何捕捉,则写成 [] 参数列表:存在两个参数 x 和 y 异变:不使用时,可省略 返回值类型:是可以省略的,编译器会自动推导 (但一般不建议省略) 函数体:要注意内部是要有分号的,代表语句结束
表达式整体代表一个lambda对象,是可以被调用的
将返回值类型省略,编译器可以自动推导
通过lambda表达式 即可清楚了解 lambda表达式对象内部如何实现比较的
若想修改升序或降序,只需修改对应的lambda表达式代码即可
捕捉列表和异变的使用
若不进行任何捕捉,使用lambda表达式完成交换
传值捕捉
若想用外面域的变量,则需要捕捉, 捕捉多个值,用逗号分割
由于是传值捕捉,所以捕捉过来的a和b是外面的拷贝,是无法改变的
异变的使用
加入mutable 异变
,即可修改传值捕捉所过来的a和b 但是无法完成交换,传值捕捉所进行的修改,并不会影响 本身
引用捕捉
使用引用的方式,即可通过修改捕捉后的a和b,来影响本身 的值进行修改
混合捕捉
a引用捕捉,b传值捕捉
假设有一堆的变量,不想一个一个捕捉 使用 [&] 即全部使用引用捕捉
使用 [=] 即全部使用传值捕捉
除了a使用传值捕捉以外,其他全部使用引用捕捉
3. 线程与lambda表达式之间的关系
pthread库是 POSIX线程库,POISIX(可移植操作系统接口) windows 与linux 下的库是不一样的
C 11中,linux和windows下都支持多线程程序 即 使用 thread库
第一个参数 作为模板类型,所以可以是 函数指针 、仿函数对象 或 lambda对象 为可调用的对象即可
对于第二个参数 Args&&....args来说 通过模板的可变参数,想传几个参数都可以 使用万能引用,当为左值时,发生引用折叠,即可以看作是& ,调用深拷贝 当为右值时,发生移动构造,进行资源转移
对于thread库的调用,与linux中的pthread库大部分功能都是类似的, 如:join 与 pthread_jojn 功能相同 ,线程等待 若一个新线程被创建出来,需要主线程就等待的 detach 与pthread_detach 功能相同,线程分离 默认是阻塞的 ,即主线程等待 新线程退出,主线程 想做其他事情
线程与lambda的结合使用
使用lambda对象 作为可被调用对象 通过lambda表达式对象, 先将 a进行传值捕捉,将1作为sum ,再进行循环 再将 b进行传值捕捉,将2作为sum,再进行循环
将m个线程打印n次
允许移动赋值
每次都创建一个线程,其整体可以看作是一个匿名对象,属于右值,所以进行移动赋值 将新建线程的资源转移到线程数组中
4. lambda原理
一个 lambda对象有多大?
实际上是1字节
转化为汇编探究
编译器会把lambda处理成仿函数
先查看仿函数的汇编
先调用构造函数,使r1成为仿函数对象 再调用rate类中的operator()
再查看lambda的汇编
由编译器生成一个不重复的类,(保证每个lambda都不一样),用该类调用构造函数 以及 调用类中的 operator()
仿函数汇编的调用与lambda汇编的调用都是先调用构造函数,在调用operator(),说明lambda底层就为仿函数实现的
根据仿函数,生成仿函数的类,由于仿函数的类是空类 ,所以为1字节 即lambda对象为1字节