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

C++11之包装器

包装器

1.1 function包装器

function包装器 也叫作适配器。C++中的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; } }; void test1() { // 函数指针 std::cout << useF(f, 11.11) << std::endl; // 函数对象(仿函数) std::cout << useF(Functor(), 11.11) << std::endl; // lamber表达式 std::cout << useF([](double d)->double { return d / 4; }, 11.11) << std::endl; }

通过上面的程序验证,我们会发现useF函数模板实例化了三份。包装器可以很好的解决上面的问题

function在头文件<functional>
类模板原型如下

template <class T> function; // undefined template <class Ret, class... Args> class function<Ret(Args...)>;


模板参数说明:
Ret : 被调用函数的返回类型
Args…:被调用函数的形参

1.2包装器的使用

有了包装器,我们就可以把上面的三份不同的对象存储到一个vector中

void test2() { //包装器 function<double(double)> f1 = f;//函数指针 function<double(double)> f2 = Functor();//仿函数对象 function<double(double)> f3 = [](double d)->double { return d / 4; };//lambda vector<function<double(double)>> v = { f1,f2,f3 }; double n = 3.14; for (auto f : v) { cout << f(n++) << endl; } }

使用方法如下:

int f(int a, int b) { return a + b; } struct Functor { public: int operator() (int a, int b) { return a + b; } }; class Plus { public: static int plusi(int a, int b) { return a + b; } double plusd(double a, double b) { return a + b; } }; void test4() { // 函数名(函数指针) std::function<int(int, int)> func1 = f; cout << func1(1, 2) << endl; // 函数对象 std::function<int(int, int)> func2 = Functor(); cout << func2(1, 2) << endl; // lamber表达式 std::function<int(int, int)> func3 = [](const int a, const int b) {return a + b; }; cout << func3(1, 2) << endl; // 类的成员函数 std::function<int(int, int)> func4 = &Plus::plusi; cout << func4(1, 2) << endl; std::function<double(Plus, double, double)> func5 = &Plus::plusd; cout << func5(Plus(), 1.1, 2.2) << endl; }

1.3包装器的应用

给你一个字符串数组tokens ,表示一个根据逆波兰表示法表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。

class Solution { public: int evalRPN(vector<string>& tokens) { stack<int> st; map<string, function<int(int, int)>> opFuncMap = { { "+", [](int i, int j) {return i + j; } }, { "-", [](int i, int j) {return i - j; } }, { "*", [](int i, int j) {return i * j; } }, { "/", [](int i, int j) {return i / j; } }, { "&", [](int i, int j) {return i & j; } } }; for (auto& str : tokens) { if (opFuncMap.find(str) != opFuncMap.end()) { //操作符 int right = st.top(); st.pop(); int left = st.top(); st.pop(); //通过[]去调用包装器的lambda st.push(opFuncMap[str](left, right)); } else { //操作数 // 1、atoi itoa // 2、sprintf scanf // 3、stoi to_string C++11 st.push(stoi(str)); } } return st.top(); } };

1.4 bind包装器

std::bind函数定义在头文件中,是一个函数模板,它就像一个函数包装器(适配器),接受一个可调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表。一般而言,我们用它可以把一个原本接收N个参数的函数fn,通过绑定一些参数,返回一个接收M个(M可以大于N,但这么做没什么意义)参数的新函数。同时,使用std::bind函数还可以实现参数顺序调整等操作。

/原型如下:

template <class Fn, class... Args> /* unspecified */ bind(Fn&& fn, Args&&... args); // with return type (2) template <class Ret, class Fn, class... Args> /* unspecified */ bind(Fn&& fn, Args&&... args);

可以将bind函数看作是一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对
象来“适应”原对象的参数列表。调用bind的一般形式:auto newCallable = bind(callable, arg_list);
其中,newCallable本身是一个可调用对象,arg_list是一个逗号分隔的参数列表,对应给定的
callable的参数。当我们调用newCallable时,newCallable会调用callable, 并传给它arg_list中
的参数。arg_list中的参数可能包含形如_n的名字,其中n是一个整数,这些参数是“占位符”,表示
newCallable的参数,它们占据了传递给newCallable的参数的“位置”。数值n表示生成的可调用对
象中参数的位置:_1为newCallable的第一个参数,_2为第二个参数,以此类推。

1.5 bind包装器的使用

例1:

int sub(int x, int y) { return x - y; } void test5() { //保持x-y不变 function<int(int, int)> resub1 = bind(sub, placeholders::_1, placeholders::_2); cout << resub1(10, 5) << endl; //交换x,y相减 function<int(int, int)> resub2 = bind(sub, placeholders::_2, placeholders::_1); cout << resub2(10, 5) << endl; }

例2:

int Plus(int a, int b) { return a + b; } class Sub { public: int sub(int a, int b) { return a - b; } static int plus(int a, int b) { return a + b; } }; void test6() { //表示绑定函数plus 参数分别由调用 func1 的第一,二个参数指定 std::function<int(int, int)> func1 = std::bind(Plus, placeholders::_1,placeholders::_2); //auto func1 = std::bind(Plus, placeholders::_1, placeholders::_2); //func2的类型为 function<void(int, int, int)> 与func1类型一样 //表示绑定函数 plus 的第一,二为: 1, 2 auto func2 = std::bind(Plus, 1, 2); cout << func1(1, 2) << endl; cout << func2() << endl; Sub s; // 绑定成员函数 //绑定参数不参与后面的排序 std::function<int(int, int)> func3 = std::bind(&Sub::sub, s,placeholders::_1, placeholders::_2); //对于非静态的类域中的函数要加上一个定义的对象 function<int(int, int)> func4 = bind(&Sub::sub, s,placeholders::_2, placeholders::_1); //传匿名对象最方便 function<int(int, int)> func5 = bind(&Sub::sub, Sub(), placeholders::_2, placeholders::_1); cout << func3(1, 2) << endl; cout << func4(1, 2) << endl; //对于静态的类域的函数 function<int(int, int)> func6 = bind(&Sub::plus, placeholders::_2, placeholders::_1); }

注意:bind在传类的成员函数的时候,如果该函数是静态的,就正常传,如果该函数不是静态的,就需要传类的地址,并且还需要传一个类的对象或者对象的指针。

总结:也就是当我们需要对一些函数接口进行传参顺序的改变,就可以使用bind包装器。

http://www.cnnetsun.cn/news/1966798.html

相关文章:

  • STM32光敏模块实战:从ADC采样到环境光强监测
  • 从CTF实战到代码复现:手把手教你用Python逆向分析RC4加密的crypt.exe
  • 【JVM深度解析】第22篇:JVM调优指标体系与性能分析方法论
  • Python的__annotations__:运行时类型注解访问
  • 3步解锁加密音乐:Unlock Music让你真正拥有自己的音乐文件
  • 用python解放右手系列(三) Excel自动化-告别复制粘贴的噩梦
  • AD7606并行驱动避坑指南:从时序图到代码实现的实战解析
  • 告别混乱OCR!Youtu-Parsing全要素解析实测:文本、表格、公式一个不漏
  • 从单兵到军团:2026 多智能体协作的崛起与实战全指南
  • 全球首份AGI教育影响白皮书发布(2026奇点大会闭门报告首次公开)
  • 零代码经验也能搞定的软著申请:用AI工具30分钟生成合规材料
  • 如何轻松管理FitGirl压缩版游戏?5步搞定游戏下载与启动完整指南
  • Hive Lateral View + posexplode 实战:从数据炸裂到业务洞察
  • 5分钟搞定:用BLAST快速检测fastq污染源(附Python脚本)
  • 从竖式到代码:C++高精度乘法核心实现与优化策略
  • 重塑游戏现实:用Smithbox开启数字创造新纪元
  • 我的编程成长日记|双非一本通信大三生的破局之路✨
  • 【踩坑实录】前端开发必看:一次由CSS缓存引发的线上事故与SEO反思
  • 微信小程序Canvas实战:5分钟实现图片自由拖拽+缩放旋转(附完整代码)
  • 面试经典:typedef vs 宏定义:指针类型安全大比拼
  • C++ 成员函数的指针
  • 深入ORB_SLAM2多线程:拆解Tracking、LocalMapping、LoopClosing三大核心线程如何协同工作
  • 药品说明书查询系统源码 本地数据库 PHP版本
  • 特斯拉Optimus Gen-3的视觉系统拆解:如何用FSD芯片实现99.2%识别准确率?
  • Linux:网络性能调优与 iperf3 实战指南
  • GNSS定位精度提升:从误差源到高精定位技术演进
  • AGI协作窗口期仅剩18个月?顶尖实验室内部推演:4种不可逆协作模式正在成型,你选对了吗?
  • YgoMaster:构建专属游戏王决斗环境的实战手册
  • Cursor Pro免费激活器:三步解锁AI编程神器的完整指南
  • 如何将中国行政区划数据迁移到MySQL数据库?