当前位置: 首页 > news >正文

包装器简介

可调用对象:

可以使用()运算符进行调用的对象,本质是能像函数一样使用的东西

常见课调用对象:函数指针,仿函数,lambda表达式

我们能否使用统一的方式对其封装,进行调用,这时候就可以使用包装器

function包装器

function包装器也就function适配器,function把所有可调用对象包装成统一类型,方便后续的调用

template<class F, class T> T useF(F f, T x) { static int count = 0; cout << "count:" << ++count << endl; cout << "count:" << &count << endl; return f(x); } double f(double i) { return i / 2; } struct Functor { double operator()(double d) { return d / 3; } }; int main() { // 函数指针 cout << useF(f, 11.11) << endl; // 函数对象 cout << useF(Functor(), 11.11) << endl; // lambda表达式 cout << useF([](double d)->double { return d / 4; }, 11.11) << endl; return 0; }

思考每次打印的count地址相同吗?

原因:函数指针,仿函数,lambda表达式是不同的类型,不同的类型,调用函数模板时,会实例出不同的函数,所以count在不同的函数中,地址不同

为了统一可调用对象的类型,function出现

std::function在头文件<functional>
// 类模板原型如下 template <class T> function; // undefined template <class Ret, class... Args> class function<Ret(Args...)>;

使用方式:

//第一个double为返回类型,()里面的double为需要的参数 function<double(double)> f1 = f; cout<<f1(1.2)<<endl; function<double(double)> f2 = Functor(); cout<<f2(2.2)<<endl; function<double(double)> f3= [](double d)->double { return d / 4; }; cout<<f3(3.3)<<endl;

包装器解决了可调用对象的类型问题

既然统一了类型,就可以放到容器里面,方便统一处理运用

vector<function<double(double)>> arr1 = { f1,f2,f3 }; vector<function<double(double)>> arr2 = { f,Functor(),[](double d)->double { return d / 4; } }; double n = 1.0; for (auto e : arr2) { cout << e(n++) << endl; }

对于类成员函数

class Plus { public: double plus1(double a, double b) { return a + b; } static int plus2(int a, int b) { return a + b; } }; int main() { function<double(Plus,double, double)> f1 = &Plus::plus1; function<int(int, int)> f2 = &Plus::plus2; Plus p; cout << f1(p, 1.1, 2.2) << endl;; cout << f2(2, 3) << endl; return 0; }

绑定类成员函数,首先告诉编译器是哪个类域中的函数,且需要获取函数的指针,对于类的非静态函数需要在第一个参数的传入类名,代表该位置要传this指针,原因:类的非静态函数来说,第一个参数为隐藏的this指针,但是在包装器对象调用时,我们并没有直接传类对象的地址,原因在于std::function会自动把对象转化为this指针,不用手动取&p。

对于类的静态函数,不需要传this指针,因为类的静态函数是属于整个类的,而非单个对象,对其进行包装后直接调用即可

template<class F, class T> T useF(F f, T x) { static int count = 0; cout << "count:" << ++count << endl; cout << "count:" << &count << endl; return f(x); } double f(double i) { return i / 2; } struct Functor { double operator()(double d) { return d / 3; } }; int main() { function<double(double)> f1 = f; function<double(double)> f2 = Functor(); function<double(double)> f3= [](double d)->double { return d / 4; }; useF(f1, 1.1); useF(f2, 2.1); useF(f3, 3.1); return 0; }

最后来看上面的场景:通过包装后,包装器对象掉泪函数模板,函数中count的地址是同一份地址,说明类型相同

bind

bind是一个函数模板,它就像一个函数包装器,接收一个可调用对象,生成一个新的可调用对象来适应元对象的参数列表,通俗一点来讲就是bind就是提前给函数绑定参数,一般而言,对于一个原本接收N个参数的函数,我们可以通过绑定一些参数,返回一个接收M个参数的新函数,同时bind也可以通过绑定实现参数顺序的调整

// 原型如下: template <class Fn, class... Args> bind (Fn&& fn, Args&&... args); template <class Ret, class Fn, class... Args> bind (Fn&& fn, Args&&... args);

bind的一般形式:auto newCallable=bind(callable,arg_list);

int sub(int a, int b) { return a - b; } int main() { function<int(int, int)> sub1 = bind(sub, placeholders::_1, placeholders::_2); cout << sub1(2, 1) << endl; //交换参数顺序 function<int(int, int)> sub2 = bind(sub, placeholders::_2, placeholders::_1); cout << sub2(2, 1); return 0; }

第二张图表明,bind将第一个参数绑定到形参的第二个位置,将第二个参数绑定到形参的第一个个位置,实现了参数的交换

补充:placeholders是一个命名空间,内部定义了第几个形参,_1指第一个形参,_2指第二个参数等等

一些场景中,我们希望对于函数中的形参绑定一些确定的值,满足我们的一些需求,这时我们可以使用缺省参数来对形参进行绑定一些值,但是这个绑定之后就不能修改了,这个时候,我们就可是使用bind来对形参进行绑定,绑定出来的可调用对象是独立的,可调用对象之间绑定的值互不影响

double getRate(double a, double b, double rate) { return (a + b) * rate; } int main() { function<double(double, double)> f1 = bind(getRate, placeholders::_1, placeholders::_2, 4.0); function<double(double, double)> f2= bind(getRate, placeholders::_1, placeholders::_2, 5.1); cout << f1(2, 3) << endl; cout<<f2(2,3)<<endl; return 0; }

同时注意,需要绑定的值无论在形参的什么位置,都不参与形参的顺序。

不影响placeholders的参数的顺序

对于类成员函数的绑定

class SubType { public: static int sub(int a, int b) { return a - b; } int ssub(int a, int b, int rate) { return (a - b) * rate; } }; int main() { function<int(int, int)> f1 = bind(&SubType::sub, placeholders::_1, placeholders::_2); function<int(int, int)> f2 = bind(&SubType::ssub, SubType(),placeholders::_1, placeholders::_2,3); SubType s; function<int(int, int)> f3 = bind(&SubType::ssub, &s, placeholders::_1, placeholders::_2, 3); function<int(int, int)> f4 = bind(&SubType::ssub, s, placeholders::_1, placeholders::_2, 3); cout << f1(2, 1)<<endl; cout << f2(2, 1) << endl; return 0; }

绑定类成员函数,首先要告诉编译器是哪个类域里面的函数,且需要获取函数的指针,对于非静态函数还需要获取对象或其地址,方便底层的调用,且其类成员函数参数隐藏this指针

http://www.jsqmd.com/news/542183/

相关文章:

  • X-TRACK二次开发终极指南:如何基于开源框架快速扩展新功能
  • OpenClaw定时任务:百川2-13B实现每日早报自动生成与发送
  • vLLM-v0.17.1入门必看:WebShell交互式调试LLM推理全流程
  • 真空贴体包装机哪家好?2026海产品气调包装厂家优选,实力品牌,护航保鲜全链路 - 栗子测评
  • ViGEmBus如何解决Windows游戏控制器兼容性难题?
  • 2026年热门的oa品牌公司推荐 - 品牌宣传支持者
  • 《CAN机能》开发全流程实战指南
  • Simulink与Plecs联合仿真实现三相桥式电路能量双向流动
  • 6种压缩黑科技如何彻底解决文件处理的效率难题
  • League Akari:5大核心解决方案提升英雄联盟游戏体验
  • 不换硬件,速度翻倍:本地 LLM 推理加速实战
  • 链表合并不解之处
  • 百川2-13B-4bits模型调优指南:提升OpenClaw任务执行准确率
  • 文艺复兴,什么是XSS,常见形式(二)
  • FreeRTOS任务跑飞了?结合STM32 HardFault信息,深度排查任务栈溢出与内存踩踏
  • 测试用例设计-XMind
  • 探索粗糙表面波动模型生成:打造不规则之美
  • 大模型进阶必看:Agent Skills如何让AI开发更标准化、可复用?速收藏!
  • imx6ull开发板连接移远EC20模块的GPS避坑指南(含SIM卡/USB口选择)
  • COMSOL数值模拟:N2和CO2混合气体在THM热流固三场耦合下增强瓦斯抽采
  • OpenClaw任务编排:用Qwen3.5-4B-Claude实现爬虫+分析闭环
  • 无代码爬虫方案:OpenClaw调度Qwen3.5-9B解析动态网页数据
  • SEO_2024年最新SEO策略与趋势深度解析(352 )
  • 大数据产品实战:用户画像系统的设计与实现
  • 如何实现精准歌词同步?KRC格式全解析与应用实践
  • 46页精品PPT | AI智能中台企业架构设计_重新定义制造
  • QRazyBox:5分钟解决二维码修复难题的专业工具
  • 2026年评价高的开窗透明食品纸盒推荐厂家 - 品牌宣传支持者
  • OpenClaw调参指南:nanobot镜像模型参数优化实战
  • 从编译失败到热重载失效:Mojo与Python混合开发的9类报错分类矩阵表(含错误码速查+对应RFC草案引用)