深圳专门网站建设,个人网站设计步骤,通化网站建设公司,做网站多少钱目录
前言
一.lambda的引入
二、lambda函数的使用
1.一般使用
2.引用
三、包装器
1.包装普通对象
2.包装类成员对象
3.bind 前言 学习过python的同学应该对lambda函数不陌生#xff0c;这是一个匿名函数#xff0c;不需要写函数的名字。在不会多地方调用某个简单函数…目录
前言
一.lambda的引入
二、lambda函数的使用
1.一般使用
2.引用
三、包装器
1.包装普通对象
2.包装类成员对象
3.bind 前言 学习过python的同学应该对lambda函数不陌生这是一个匿名函数不需要写函数的名字。在不会多地方调用某个简单函数的地方就可以使用lambda。
一.lambda的引入 在学习lambda函数之前我们来看一个用例。这是一些商品我们需要对商品进行排序。
struct Goods
{string _name; // 名字double _price; // 价格int _evaluate; // 评价Goods(const char* str, double price, int evaluate):_name(str), _price(price), _evaluate(evaluate){}
};
int main()
{vectorGoods v { { 苹果, 2.1, 5 }, { 香蕉, 3, 4 }, { 橙子, 2.2,3 }, { 菠萝, 1.5, 4 } };sort(v.begin(), v.end());sort(v.begin(), v.end());
}
由于商品是自定义类型比较函数要我们自己写在Goods类里面写operator很不方面。
无法使用sort函数需要自己写排序排序的方式有很多比如价格升序和降序评价的升序和降序。 因此一般情况下我们都会写仿函数来帮助我们进行比较。例如下面两个仿函数
struct CompareEvaluateLess
{bool operator()(const Goods gl, const Goods gr){return gl._evaluate gr._evaluate;}
};
struct ComparePriceGreater
{bool operator()(const Goods gl, const Goods gr){return gl._price gr._price;}
};
给sort函数传递仿函数就可以按照我们的想法进行排序了。 随着C语法的发展人们开始觉得上面的写法太复杂了每次为了实现一个algorithm算法 都要重新去写一个类如果每次比较的逻辑不一样还要去实现多个类特别是相同类的命名 这些都给编程者带来了极大的不便。因此在C11语法中出现了Lambda表达式。
二、lambda函数的使用
1.一般使用
lambda使用方法如下有点长先不用看直接看后面的例子 lambda书写格式[capture-list] (parameters) mutable - return-type { statement } [capture-list] : 捕捉列表该列表总是出现在lambda函数的开始位置编译器根据[]来 判断接下来的代码是否为lambda函数捕捉列表能够捕捉上下文中的变量供lambda 函数使用。(parameters)参数列表。与普通函数的参数列表一致如果不需要参数传递则可以 连同()一起省略mutable默认情况下lambda函数总是一个const函数mutable可以取消其常量性。使用该修饰符时参数列表不可省略(即使参数为空)。 -returntype返回值类型。用追踪返回类型形式声明函数的返回值类型没有返回值时此部分可省略。返回值类型明确情况下也可省略由编译器对返回类型进行推导。{statement}函数体。在该函数体内除了可以使用其参数外还可以使用所有捕获到的变量。 举个例子如下[]为捕捉列表先不捕捉后续会讲(int x)为参数-int返回类型为int{}里面存放函数内容。
[](int x)-int {cout x endl; return 0; };
如下两个方法可以进行lambda函数的调用 第一个是直接在后面给参数调用。 第二个是赋值给auto 变量再使用该变量名进行调用。 对于之前商品排序现在我们也会修改了一下子就搞定了。 2.引用
方法一参数传引用这是我们熟悉的方法由于不需要返回参数因此省略-()。如下 方法二捕获列表 使用正常捕获是const的无法修改需要加mutable变为可修改见二、1使用方法第三条。使用引用捕获不加mutable也可以修改引用的目的大多是为了修改这里编译器做了特殊处理。如下引用捕获了x和y同时也不需要传参了因为我们使用了捕获列表参数列表没有参数。 引用捕获列表还可以使用代表引用捕捉当前作用域中的所有变量如下这里只有xy。 三、包装器
1.包装普通对象
function包装器也叫作适配器。他的主要目的是为了包装可调用对象主要的可调用对象有函数指针仿函数lambda。
为什么要包装可调用对象呢我们来看看他们的弊端。 函数指针用起来太不方便了写起来很难受。 仿函数需要在全局定义不够简洁和美观。 lambda类型是匿名的一般取不到类型。 如果现在我想像cmd命令一样输入一个指令计算机进行相应的操作这个操作就可以是相关的函数那么我可以进行如下定义。使用map的operator[]进行相关操作红色方框的类型应该填什么呢写函数指针和仿函数很不方便写lambda类型都没有没办法写。这时就需要包装器上场了。 比如我要进行数字的加减乘除操作我们可以这样传递第二个参数functiondouble(double a,double b)这样代表包装的可调用对象的类型。那么我们实际传参时只要类型相同既可以传递函数指针又可以传递仿函数还可以传递lambda匿名对象这样非常方便。注意添加头文件#include functional如下所示 2.包装类成员对象
代码如下
class Add
{
public:static int addi(int a, int b){return a b;}double addb(double a, double b){return a b;}
};int main()
{functionint(int, int) f1 Add::addi;cout f1(5, 3) endl;
} 包装类里面的静态函数指定类域即可直接包装最好填也可以不填。 如果是非静态呢 由于类的非静态变量有this指针因此这里编译不通过。 我们可以给第一个参数传递类指针再定义一个类对象取地址传过去就可以了。
还有一种写法算是编译器的特殊处理可以不用再生成类对象。 但是始终这个方法不太好本来我就只想传两个参数你一定要让我传第一个一直固定的不是多此一举嘛这时bind函数就出场了。
3.bind
bind也是在头文件functional里面的他的作用是绑定函数让函数参数变成我们想要的个数和顺序。
如下绑定了一个减法lambda函数第一个参数使用placeholders作用域_2代表前面那个函数的第二个参数第二个参数为该作用域下的_1代表前面那个函数的第一个参数。相当于10给到了y3给到了x因此输出结果是-7。 如果我们给lambda函数第一个参数x为固定值如下给20那么我们需要将前面function的参数个数减少一个同时调用的时候也只需要传一个参数也就是placeholders::_1因为只有一个参数。 当然第二个参数也可以给固定值。 学会了基本用法我们回过头来修改类的成员函数。将function只设置两个参数同时将Add::addb函数的第一个参数固定死传Add()后续再传placeholders::_1, placeholders::_2代表实参的第一个和第二个就好。 这样就可以按照我们的想法进行传参了。
谢谢大家观看