当前位置: 首页 > 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.jsqmd.com/news/662262/

相关文章:

  • 从Deformable DETR到DINO:混合查询选择,如何让模型‘看’得更准?
  • 别再被‘子仓库’报错吓到!手把手教你用git submodule搞定项目依赖管理
  • 实战指南:5步构建跨平台AI自动化测试体系
  • 2026年行业内轻集料混凝土生产厂,轻骨料混凝土/干拌复合轻集料/lc5.0轻集料混凝土,轻集料混凝土生产商哪家好 - 品牌推荐师
  • AGI到底强在哪?2026奇点大会首次公开12维能力评估矩阵:含推理深度、跨域泛化率、因果鲁棒性实测数据
  • ChatLog:解锁QQ群聊天数据的终极分析工具
  • 自动驾驶中的占用感知综述:信息融合视角
  • 利用OWL ADVENTURE进行软件测试:自动化视觉回归测试与UI缺陷检测
  • 如何快速掌握抖音下载器:面向内容创作者的完整工具指南
  • WPF布局
  • 银行数据中心基础设施建设与运维管理【2.2】
  • 总结java学习one -
  • 软件服务管理化的客户价值创造
  • 网络安全技术思考
  • 从CTF实战到代码复现:手把手教你用Python逆向分析RC4加密的crypt.exe
  • ZeroPoint Security red team ops I CRTO 6 Persistence
  • 避坑!这些毕设太好抄了,3000+毕设案例推荐第1077期
  • 【点云处理之理论基石】—— Deep Sets:从集合不变性到点云分类的通用架构
  • AI教育平台开发技术框架
  • 从《倘若鸟儿回还》看无障碍设计:如何用技术为轮椅用户打造真正的“独立出行”体验
  • Untrunc终极指南:免费开源视频修复工具,拯救损坏的MP4/MOV文件
  • 1982-2010年陆地植被碳密度数据集
  • 突破限制!NVIDIA Profile Inspector深度调校指南:解锁显卡隐藏性能的终极秘籍
  • Linux内核中的网络管理详解
  • 微软为什么发明 SqlLocalDB?命令行直接启动,0配置成本
  • FireRed-OCR Studio入门必看:@st.cache_resource缓存机制原理与实测提速
  • 漫画离线阅读终极指南:如何轻松下载8大网站漫画内容
  • 终极指南:如何用LayerDivider实现插画智能分层与PSD自动生成
  • 一物一码系统功能点,如何重构快消增长与渠道管理
  • MCU深度学习新选择:如何用NNoM在微控制器上部署神经网络模型?