一.lambda
1.lambda的语法
①.定义
lambda表达式是一个匿名函数对象,跟普通函数只能定义在全局,或者类里不同,它能够定义在函数的内部。
②.类型
lambda表达式在使用层而言没有类型,一般用auto或者模板参数定义的对象去接收lambda对象。
③.lambda的格式
表达式格式跟普通函数相比,少了函数名(匿名),多了捕捉列表。
一个小示例:
注:此处修正一下,返回值部分是“->返回值类型”。没有返回值,可以不写。
2.lambda的用途
从图中可看出利用lambda写出的控制升降序的可读性大大提升。
3.capture-list(捕捉列表)重点!!!!
3-1.用法
lambda能够直接使用全局域或者lambda局部域内的变量,要想使用其他局部域的变量,需要借助捕捉列表。注意,同一个变量不能被同时捕捉两次!!!!
3-2.分类
捕捉分为三个大类:显示捕捉和隐式捕捉以及混合使用显示和隐式捕捉。
3-3.显示捕捉
①.其中显示捕捉可分为值捕捉和引用捕捉。
②.引用捕捉的引用有些特殊,不需要变量的类型,只需要一个“&+变量"就行了。
③.由于值捕捉过来的变量是被const修饰的,因此无法修改,而引用捕捉过来的变量可以修改。
但实在要修改值捕捉的变量,可以在函数体前添加一个关键字——mutable,取消const:
不过由于是传值捕捉,变量在类域内大小改变,但出了类域,变量大小不变。
④.引用捕捉到的变量在类域内修改后,其在类域外变量的大小也会改变,因为捕捉到的是个引用,是个别名。
3-4.隐式捕捉
①.隐式捕捉仍旧分成隐式值捕捉和隐式引用捕捉。
②.隐式值捕捉
示例:
③.隐式引用捕捉
示例:
3-5.混合使用显示和隐式捕捉
形式Ⅰ.个别(a,b)显示传值,其他全为引用捕捉,因此用上隐式传引用,自动捕捉c,d:
形式Ⅱ.个别传值引用捕捉,其余全是传值,因此用上隐式传值捕捉,自动捕捉c,d:
4.lambda的原理
①.其原理与范围for相似,二者都属于上层的东西,在汇编层面根本就没有范围for和lambda的说法,lambda的底层是个仿函数对象,写一个lambda后,编译器会自动生成一个对应仿函数的类。
②.并且类名由编译器决定,下面蓝色区域就是类名,由lambda+后面uuid(一串字符串)组成,是独一无二的。
③.lambda的参数,返回值类型和函数体就是其对应仿函数中operator()的参数,返回值类型和函数体。而捕捉列表是仿函数类的成员变量。
二.包装器
1.function
①.定义
注意:使用function的时候要包含头文件:<functional>
②.格式
③.意义
统一可调用对象的类型。
所谓统一类型,其实是将不同类型的可调用对象,分别作为不同function的成员,经过这样的封装以后,暴露出的类型全是function类型。
由图可知,f,Functor(),lambda这三个可调用对象的类型必然是不同的,要想同一类型,就用function,包装后的f1,f2,f3的类型是相同的。
④.包装成员函数
Ⅰ.需要指定类域
Ⅱ.非静态成员函数还必须在类域前加"&"(取地址)操作符,静态的可加可不加,建议也加上。
Ⅲ.但即便有了取地址操作符,还是会报错,这是什么原因?原因在于非静态成员函数的参数里还有隐藏的this指针,所以包装时,还需要在可变参数模板里加上对象或者对象的指针:
2.bind
①.定义
②.作用
Ⅰ.调整参数顺序(意义不大)
Ⅱ.调整参数个数
注意:_n代表第n个实参,因此sub6第三个参数是_2的1而不是_3
三.类的新功能
1.默认移动构造和移动赋值
c++11增加了两个默认成员函数,即默认移动构造和移动赋值。这俩玩意在笔者c++11(二)里的第2节和c++11(一)的第6节都提过一嘴,这里还剩下部分内容。