360建筑网简历怎么删除,开鲁网站seo转接,微信答题抽奖小程序制作,郑州网站制作汉狮该篇为lambda表达式的延申#xff0c;请在熟知lambda表达式的基础上阅读该文章 一文详解C11lambda表达式https://blog.csdn.net/qq_74260823/article/details/134839319?spm1001.2014.3001.5501 包装器的由来
这同样是一个不属于C原始风味的语法 我们在lambda表达式中讲到过… 该篇为lambda表达式的延申请在熟知lambda表达式的基础上阅读该文章 一文详解C11lambda表达式https://blog.csdn.net/qq_74260823/article/details/134839319?spm1001.2014.3001.5501 包装器的由来
这同样是一个不属于C原始风味的语法 我们在lambda表达式中讲到过就算lambda表达式是相同的其类型也不同不能进行相互赋值等操作。而这还只是在lambda表达式之间如果有一个仿函数和一个lambda表达式就算其功能相同我们想把他们联系起来那也堪比登天一般难。
//仿函数
struct plus
{int operator()(int num1, int num2){return num1 num2;}
};int main()
{//lambda表达式auto lambda_plus [](int a, int b) {return a b; };//两者功能相同却不能相互联系lambda_plus plus();
}
就好比…… 这就导致在很多应用场景lambda表达式和仿函数使用起来是非常不便的。比如之前我们大量进行回调函数时会采用函数指针的方式构建一个函数指针数组调用时按其对应的下标调用即可。但是lambda表达式则不然每一个lambda表达式类型都不同我们没办法去开辟一个定类型的数组也就意味着传统的函数指针的方式是不可行的。 于是带着这个使命包装器便产生了 包装器 包装器的作用是将函数仿函数lambda表达式的类型统一使其可以相互联系相互转化 包装器的定义
包装器在头文件functional中其定义长这个鬼样子 其中ret代表返回值的类型而Args代表参数包的类型。 直接来看例子吧以加法的函数为例
也就是说在function的模板里第一个参数是返回值的类型随后在括号里依次传入函数参数列表的类型一一对应 而后赋值的时候只需要让其等于已经定义过的可调用对象便完成了赋值可以正常进行使用。
包装器的类型
还是刚刚的例子我们分别包装函数函数指针仿函数lambda表达式看看其类型的情况
//函数
int normal_plus(int num1,int num2)
{return num1 num2;
}//仿函数
struct functor_plus
{int operator()(int num1, int num2){return num1 num2;}
};int main()
{//lambda表达式auto lambda_plus [](int a, int b) {return a b; };//使用包装器包装函数functionint(int, int) function1 normal_plus;//使用包装器包装函数指针functionint(int, int) function2 normal_plus;//使用包装器包装仿函数functionint(int, int) function3 functor_plus();//使用包装器包装lambda表达式functionint(int, int) function4 lambda_plus;//其类型都为class std::functionint __cdecl(int,int)cout typeid(function1).name() endl;cout typeid(function2).name() endl;cout typeid(function3).name() endl;cout typeid(function4).name() endl;//也可以进行相互转化function1 function2;
}
最终无论最开始他们是什么类型到了最后都变成了类似于functionint(int,int)的类型也就可以进行相同类型之间的任何操作 包装器的应用场景
通过包装器我们可以轻轻松松实现函数回调
int main()
{//实现一个计算器mapstring, functionint(int, int) calculator {{加法,[](int a,int b) {return a b; }},{减法,[](int a,int b) {return a - b; }},{乘法,[](int a,int b) {return a * b; }},{除法,[](int a,int b) {return a / b; }}};calculator[加法](1, 20);
}
如果没有包装器那么只能采用普通函数构建函数指针数组既会产生大量命名冲突的风险又会导致程序的简洁性大大降低。但是采用包装器便把lambda表达式简洁易读的特点放到了最大。
包装器存在的问题
如果我们需要包装一个类中函数我们应该怎么办 class Plus
{
public:static int plusi(int a, int b){return a b;}double plusd(double a, double b){return a b;}
};int main()
{//静态成员函数——没有this指针std::functionint(int, int) funci Plus::plusi;//可以不写cout funci(1, 2) endl;//非静态——有this指针std::functiondouble(Plus, double, double) funcd Plus::plusd;//包装的时候必须有一个this的位置必须写cout funcd(Plus(), 1.1, 2.2) endl;//通过匿名对象调用成员函数return 0;
}
如果是类中的静态函数则和调用普通函数相同而如果是类中非静态函数则必须要在参数列表中加上this指针的类型并且赋值时只能赋值为函数指针调用时也必须传入this指针 但是往往我们使用的时候并不喜欢每次都写this指针那有没有办法省略掉this指针呢
当然这便是新的特性bind bind
std::bind函数定义在头文件中是一个函数模板它就像一个函数包装器(适配器)接受一个可调用对象callable object生成一个新的可调用对象来“适应”原对象的参数列表。一般而言我们用它可以把一个原本接收N个参数的函数fn通过绑定一些参数返回一个接收M个M可以大于N但这么做没什么意义参数的新函数。同时使用std::bind函数还可以实现参数顺序调整等操作。
bind的定义 继续看例子吧
也就是说bind实际上是拷贝了其他函数或包装器来定义一个新的包装器在bind的第一个参数中我们输入被绑定的名称在后面依次输入参数的顺序一直到参数的个数与被绑定的函数的参数个数相同。
这个参数个数我们可以进行一些小调整
强制参数
int normal_plus(int num1, int num2)
{return num1 num2;
}int main()
{//第一个参数强制传入10//包装器模板参数中只需要传入一个参数//而参数的顺序为剩下参数的顺序functionint(int) fplus bind(normal_plus, 10, placeholders::_1);//调用时只需要传入一个参数fplus(2);//102
}
交换参数的顺序
int normal_plus(int num1, int num2)
{return num1 num2;
}int main()
{//交换参数的顺序functionint(int, int) fplus bind(normal_plus, placeholders::_2,//第一个参数传入num2placeholders::_1//第二个参数传入num1);//传入的参数顺序为绑定的顺序fplus(10, 3);//310;
}
而通过这种方法我们便可以写死this指针不需要每次都传入this了