C++11(4):

1. Lambda:

今天我们来学习一下lambda,这个lambda是什么呢?

我们的C++的可调用对象有函数指针,仿函数,我们之前的时候,仿函数的话,我们的仿函数使用在很多地方,比如升降排序,还有我们的红黑树和哈希表里面,我们都有使用,我们这里的lambda的话,其实和仿函数比较类似,只是说我们有的地方使用仿函数的话,比较小题大做的感觉,所以,我们这里也可以使用lambda来解决。

lambda有点不像我们的传统的C++,我们的C++11之后,我们也可以称之为现代C++。

这个就是我们写的一个lambda,他是一个匿名的对象,他的类型我们是取不到的,我们就必须得使用auto,它的类型我们是不知道的。

但是假如我们真的需要知道lambda的类型的时候,我们也可以使用decltype,decltype可以推出一个对象的类型,把我们的lambda作为对象传进去就可以得到他的类型。

因为他的类型我们是不知道的,我们就使用一个auto来代替,让我们的编译器来进行推导。

然后我们的这个对象就可以像函数一样的去使用了,我们说他和我们的仿函数比较类似,我们的仿函数的类实例化的对象就可以像函数一样的去使用。

我们看这个我们写的lambda,他的运行的结果就是3,这个lambda就是一个局部的匿名函数对象,比起函数指针比较方便,比起仿函数比较轻,不需要定义类,可以直接在局部,现定义,现用。这个就是我们的lambda的特点;

我们继续看:

对于lambda,我们讲述了四点,第一点是我们的捕捉列表是不能省略的,即使是为空也是不能省略,第二点是我们的参数为空的时候,我们是可以省略的,我们的lambda没有参数的时候,我们的参数列表可以省略,第三点是,我们的返回值可以省略,我们的返回值可以通过我们的返回对象进行推导,第四点是,我们的函数体是不能省略的。

我们看上面的图片,上面的lambda,我们省略了返回值的类型,然后下面的lambda,我们省略了参数列表和返回值的类型。

然后我们下面func1();这个lambda就可以像函数一样的去使用。(和仿函数实例化的对象一样,可以像函数一样的使用)。

然后我们再写一个lambda:

我们看上面的我们写的lambda,

1. 捕捉列表:

lambda一般不写在全局,一般写在局部。

lambda默认只能使用lambda函数体和参数里面的变量的,其他的外层的变量是不能使用的。  所以如果想使用外层作用域的变量的话,就需要捕捉。

我们看上图,这是我们的第一种捕捉方式:

显示捕捉:传值捕捉和传引用捕捉,我们把a的值拷贝一份进来,然后b是传引用,就是把b的别名传进来,传进来的a我们不能修改,因为捕捉列表(的传值捕捉)默认被const修饰,传值进来的不能修改,传引用进来的可以修改。

然后我们看第二种捕捉:

隐式捕捉:

隐式捕捉有两种:第一种是隐式值捕捉,我们在捕捉列表里面加上=,这样的话,我们的lambda里面使用了什么变量,我们的捕捉列表就会捕捉什么变量,当然,我们值捕捉的变量是不能修改的,然后第二种是隐式传引用拷贝,我们在捕捉列表里面加上&,lambda里面使用什么变量,我们就会捕捉什么变量,当然,我们捕捉到的变量是变量的引用,我们可以进行修改。

那还有第三种情况:那就是,我们所有的变量都想捕捉,但是某一个值我们想要传引用的进行捕捉

第三种:

显示捕捉和隐式捕捉混合使用:

我们所有的变量都想捕捉(传值捕捉或者传引用捕捉),但是某一个值我们想要(和前面不同的传值捕捉或传引用捕捉)。

捕捉列表第一个必须是&或者=;

我们看上图,当我们所有的变量都想是传引用捕捉,但是其中的变量a,我们想要是使用传值捕捉,其他变量都可以修改,但是我们的a变量不能修改。

2. lambda的使用:

我们看我们的排序算法sort,函数的最后我们的compare 我们要传可调用对象,这个可调用对象要支持两个数据的比较,我们可以传函数指针,可以传仿函数,来实现我们的比较逻辑。

我们先看这个图片:

我们的Goods是我们的一个类,表示一个水果和他的价格以及评价,然后我们实例化一个vector,vector里面存储的Goods类型的数据,然后我们给vector进行初始化。

我们现在要求给我们的vector里面的数据进行排序。我们可以使用sort排序算法。

后面的compare我们要传一个可调用对象进去(表示我们的排序的逻辑)

我们看图片中的仿函数,我们是把Goods里面的价格拿出来进行比较,(我们的仿函数只要实现两个Goods的比较逻辑就可以了,其他的不用管,我们的sort排序里面其他的逻辑已经实现好了)。   这个就可以对我们的水果类Goods进行排序;

我们上面的可调用对象是传了一个仿函数进去;

我们也可以是传一个lambda进去:就是我们的第一个图片中的;

我们看我们的红线的部分,我们之前是仿函数,现在我们这里是lambda;

这里的小于是升序;大于是降序;

3. lambda的底层:

我们的lambda的底层其实还是我们的仿函数,就像我们的范围for的底层是我们的迭代器一样;

2. 包装器:

1. function:

我们的function的功能是包装可调用对象,可调用对象包括:函数指针,仿函数,lambda;

他的特点是可以统一可调用对象的类型;

我们看上面的图片,假如我们没有包装器的话,我们想把上面的函数,仿函数,lambda都存放到我们的vector的话,这根本做不到,我们的vector实例化什么类型都不知道。

我们上面的三种可调用对象的参数,返回值都是一样的,都是int类型的,我们就可以把他们三个都套上function的包装器,然后把他们三个放到vector里面去,,然后我们的vector可以使用范围for调用他们三个,

这个调用其实和这个operator()是一样的。func();

我们继续看:

我们也可以包装我们的成员函数:

当我们包装静态的成员函数的时候function<>尖括号里面写上我们的函数的返回值类型和参数类型,然后后面是我们的类域跟上成员函数,(前面加上取地址符号)。

当我们包装的是普通的成员函数的时候,我们的参数列表的第一个要加上我们的this指针,this指针是我们的实例化的对象取地址得到的,那么他的类型就是我们的类的地址。

2. bind:

我们看另一个包装器bind;bind是一个函数模板,上面的function是一个类模板;

bind可以用来调整可调用对象的参数个数和参数顺序。

首先,我们看调整我们的可调用对象的参数的顺序,我们的bind中的_1表示第一个实参,_2表示第二个实参,,,

然后我们看上图:Sub函数当我们传1,2进去的时候,算出来的结果是-10,但是我们现在想改变一下我们的参数的顺序,我们想把1传进去的时候,他会走到第二个实参的位置,然后2传进去的时候,他会走到第一个实参的位置。(这个我们其实并不常用)

更常用的玩法是什么呢?

调整我们的参数个数:

我们看上面的图片是调整参数个数的,第一下,我们给b绑死,绑上10,然后第一个实参还是_1,(_1代表第一个实参),然后下面调用Sub2(1)函数,1传给了第一个实参,第二个参数的话,我们可以理解为缺省值。

然后下面是把我们的a绑死,绑上10,然后b就是我们的第一个实参,那就是_1,然后我们调用函数传1进去,结果为90;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值