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

深入解析:【C++:C++11收尾】解构C++可调用对象:从入门到精通,掌握function包装器与bind适配器包装器详解


在这里插入图片描述

个人主页艾莉丝努力练剑

专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录
Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享

⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平

艾莉丝的简介:

在这里插入图片描述


艾莉丝的C++专栏简介:

在这里插入图片描述


文章目录

  • C++学习阶段的三个参考文档
  • 8 ~> 包装器
    • 8.1 function
      • 8.1.1 结构
      • 8.1.2 概念
      • 8.1.3 function实现
      • 8.1.4 重写逆波兰表达式求值
    • 8.2 bind
      • 8.2.1 结构
      • 8.2.2 概念
      • 8.2.3 代码实现
  • 9 ~> 智能指针预告
  • C++11完整代码示例与实践演示
    • Test.cpp:
  • 结尾


C++学习阶段的三个参考文档

看库文件(非官方文档):Cplusplus.com

在这里插入图片描述

这个文档在C++98、C++11时候还行,之后就完全没法用了……

准官方文档(同步更新)——还 可以看语法C++准官方参考文档

在这里插入图片描述
这个行,包括C++26都同步了,我们以后主要会看这个。

官方文档(类似论坛):Standard C++

在这里插入图片描述
这个网站上面会有很多大佬,类似于论坛。


在这里插入图片描述


8 ~> 包装器

8.1 function

8.1.1 结构

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

8.1.2 概念

std::function 是一个类模板,也是一个包装器 std::function 的实例对象可以包装存储其他的可以调用对象,包括函数指针、仿函数、lambdabind表达式 等,存储的可调用对象被称为 std::function 的目标。若std::function不含目标,则称它为空。调用空 std::function 的目标导致抛出std::bad_function_call异常。

在这里插入图片描述

以上是function的原型,他被定义头文件中。std::function是function的官方文件链接。

在这里插入图片描述

函数指针、仿函数、 lambda 等可调用对象的类型各不相同, std::function 的优势就是统一类型,对他们都可以进行包装,这样在很多地方就方便声明可调用对象的类型,下面的第二个代码样例展示了 std::function 作为map的参数,实现字符串和可调用对象的映射表功能。

8.1.3 function实现

在这里插入图片描述
在这里插入图片描述

8.1.4 重写逆波兰表达式求值

力扣题目链接:150. 逆波兰表达式求值

力扣题解链接:后缀法 && 操作符紧跟操作数 && switch…case…语句解决

这道题我们已经写过一次了,这次我们会采用另一种方式实现。

题目描述:

在这里插入图片描述
对应博客链接:【C++STL :stack && queue (一) 】STL:stack与queue全解析|深入使用(附高频算法题详解)

在这里插入图片描述

传统方式实现(之前的实现)——

class Solution {
public:
int evalRPN(vector<string>& tokens) {stack<int> st;for(auto& str : tokens){// 判断四种运算符if(str == "+" || str == "-" || str == "*" || str == "/"){// 运算符int right = st.top();st.pop();int left = st.top();st.pop();switch(str[0]) // 大坑:switch...case语句只能是int类型{case '+':st.push(left + right);break;case '-':st.push(left - right);break;case '*':st.push(left * right);break;case '/':st.push(left / right);break;}}else{// 运算数st.push(stoi(str)); // 字符串转整型,to_string}}return st.top();}};

我们可以现学现用,使用map映射string和function的方式实现一下——

在这里插入图片描述
这种方式的最大优势之一是方便扩展,假设还有其他运算,我们增加map中的映射即可,算法实现如下所示——

class Solution{
public:
int evalRPN(vector<string>& tokens) {map<string,function<int(int,int)>> opFuncMap ={{"+",[](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;}}};stack<int> st;for(auto& str : tokens){if(opFuncMap.count(str)){// 运算符int right = st.top();st.pop();int left = st.top();st.pop();int ret = opFuncMap[str](left,right);st.push(ret);}else{// 运算数st.push(stoi(str));}}return st.top();}};

8.2 bind

8.2.1 结构

simple(1)
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);

8.2.2 概念

bind 是一个函数模板,它也是一个可调用对象的包装器,可以把他看做一个函数适配器,对接收的fn可调用对象进行处理后返回一个可调用对象。 bind 可以用来调整参数个数和参数顺序。 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 / _2 / _3…这些占位符放到placeholders的一个命名空间中。

在这里插入图片描述

8.2.3 代码实现

在这里插入图片描述


9 ~> 智能指针预告

C++专栏的主线内容马上就要结束啦,艾莉丝将把智能指针作为C++干货专栏的主线(C++98、C++11部分)的终章,之后本专栏还会更新,内容以C++11、C++14、C++17、C++20、以及其它的加餐内容为主了。感谢大家对艾莉丝的支持!希望uu们能够继续支持艾莉丝哦!感谢大佬们的支持!


C++11完整代码示例与实践演示

Test.cpp:

#define  _CRT_SECURE_NO_WARNINGS  1
#include<iostream>#include<vector>#include<functional>using namespace std;// ===================C++11:包装器=================//--------------------function---------------------int f(int a, int b){return a + b;}struct Functor{public:int operator()(int a, int b){return a + b;}};class Plus{public:Plus(int n = 10):_n(n){}static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return (a + b) * _n;}private:int _n;};//int main()//{//	// 类型擦除//	function<int(int, int)> f1 = f;//	function<int(int, int)> f2 = Functor();//	function<int(int, int)> f3 = [](int a, int b) {return a + b; };//	cout << f1(1, 1) << endl;//	cout << f2(1, 1) << endl;//	cout << f3(1, 1) << endl;////	vector<function<int(int, int)>> v;//	v.push_back(f);//	v.push_back(Functor());//	v.push_back([](int a, int b) {return a + b; });////	for (auto& f : v)//	{//		cout << f(1, 1) << endl;//	}//	cout << endl;////	//function<int(int, int)> f4 = Plus::plusi;//	function<int(int, int)> f4 = &Plus::plusi;//	cout << f4(1, 1) << endl;////	function<double(Plus*, double, double)> f5 = &Plus::plusd;//	Plus ps;//	cout << f5(&ps, 1.1, 1.1) << endl;////	function<double(Plus, double, double)> f6 = &Plus::plusd;//	cout << f6(ps, 1.1, 1.1) << endl;////	function<double(Plus, double, double)> f7 = &Plus::plusd;//	cout << f7(Plus(), 1.1, 1.1) << endl;		// Plus():匿名对象////	function<double(Plus&&, double, double)> f8 = &Plus::plusd;//	cout << f8(Plus(), 1.1, 1.1) << endl;////	auto pf1 = &Plus::plusd;//	Plus* ptr = &ps;//	cout << (ps.*pf1)(1.1, 1.1) << endl;//	cout << (ptr->*pf1)(1.1, 1.1) << endl;	// 无法显式传this指针////	return 0;//}// 运行结果:// 2// 2// 2// 2// 2// 2// // 2// 22// 22// 22// 22// 22// 22// ------------------bind-------------------// _n占位using placeholders::_1;using placeholders::_2;using placeholders::_3;int Sub(int a, int b){return (a - b) * 10;}int SubX(int a, int b, int c){return(a - b - c) * 10;}int main(){// bind的本质是返回一个仿函数对象// 调整参数顺序(这个功能不常用)// _1代表第一个实参// _2代表第二个实参// ...// 交换auto f1 = bind(Sub, _1, _2);auto f2 = bind(Sub, _2, _1);// _1代表第一个实参// _2代表第二个实参cout << f1(10, 5) << endl;cout << f2(10, 5) << endl;// 调整参数个数auto f3 = bind(SubX, 10, _1, _2);cout << f3(15, 5) << endl;// _1代表第一个实参// _2代表第二个实参// 底层operator(),调用SubX,第一个参数10, 15, 5auto f4 = bind(SubX, _1, 10, _2);cout << f4(15, 5) << endl;// 底层operator(),调用SubX,第一个参数15, 10, 5auto f5 = bind(SubX, _1, _2, 10);cout << f5(15, 5) << endl;// 底层operator(),调用SubX,第一个参数15, 5, 10function<double(Plus, double, double)> f7 = &Plus::plusd;cout << f7(Plus(), 1.1, 1.1) << endl;cout << f7(Plus(), 2.2, 1.1) << endl;cout << f7(Plus(), 3.3, 1.1) << endl;function<double(Plus&&, double, double)> f8 = &Plus::plusd;cout << f8(Plus(), 1.1, 1.1) << endl;cout << f8(Plus(), 2.2, 1.1) << endl;cout << f8(Plus(), 3.3, 1.1) << endl << endl;// 计算复利(利息)的lambdaauto func1 = [](double rate, double money, int year)->double {double ret = money;for (int i = 0; i < year; i++){ret += ret * rate;}return ret - money;};// 年利率1.5%function<double(double)> func_r1_5_3y = bind(func1, 0.015, _1, 3);function<double(double)> func_r1_5_5y = bind(func1, 0.015, _1, 5);function<double(double)> func_r1_5_20y = bind(func1, 0.015, _1, 20);// 本金100000元cout << func_r1_5_3y(100000) << endl;cout << func_r1_5_5y(100000) << endl;cout << func_r1_5_20y(100000) << endl;// 这只股票如果利率有10%呢function<double(double)> func_r10_3y = bind(func1, 0.1, _1, 3);function<double(double)> func_r10_5y = bind(func1, 0.1, _1, 5);function<double(double)> func_r10_20y = bind(func1, 0.1, _1, 20);cout << func_r10_3y(100000) << endl;cout << func_r10_5y(100000) << endl;cout << func_r10_20y(100000) << endl;// 如果你的10万元到了“股神”巴菲特手里------19%,同样的时间会怎么样?function<double(double)> func_r19_3y = bind(func1, 0.19, _1, 3);function<double(double)> func_r19_5y = bind(func1, 0.19, _1, 5);function<double(double)> func_r19_20y = bind(func1, 0.19, _1, 20);cout << func_r19_3y(100000) << endl;cout << func_r19_5y(100000) << endl;cout << func_r19_20y(100000) << endl;return 0;}// 运行结果:// 50// -50// -100// 0// 0// 22// 33// 44// 22// 33// 44// // 4567.84// 7728.4// 34685.5// 33100// 61051// 572750// 68515.9// 138635// 3.14294e+06

结尾

uu们,本文的内容到这里就全部结束了,艾莉丝再次感谢您的阅读!

结语:希望对学习C++相关内容的uu有所帮助,不要忘记给博主“一键四连”哦!

往期回顾

【C++:C++11】C++11新特性深度解析:从可变参数模板到Lambda表达式

博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!
૮₍ ˶ ˊ ᴥ ˋ˶₎ა

在这里插入图片描述

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

相关文章:

  • 【大模型本地化新突破】:Open-AutoGLM离线部署性能提升300%的秘密
  • Open-AutoGLM刷机风险与收益全解析,90%用户不知道的安全隐患
  • 【Open-AutoGLM手机自动化秘籍】:手把手教你实现零代码智能操作
  • MySQL.Data.dll终极下载指南 - 全面覆盖各版本.NET MySQL连接组件
  • 2025年靠谱的空气密封圈厂家最新用户好评榜 - 品牌宣传支持者
  • 【大模型提示词新范式】:基于Open-AutoGLM的6大工业级应用场景详解
  • TensorFlow与Dash集成:构建专业AI仪表盘
  • 物理信息神经网络实战手册:7天从零掌握科学计算革命性技术
  • 如何通过TensorFlow镜像节省算力开销?实战案例分享
  • 基于TensorFlow的图像分类项目全流程教学
  • 2025年质量好的郑州cpvc电力管/mpp电力管用户好评厂家排行 - 品牌宣传支持者
  • 从代码执行到价值整合:LLM时代程序员的“问题域全栈”转型研究
  • 终极指南:如何用ComfyUI Workspace Manager高效管理工作流
  • 2025年度苗木批发基地排行榜揭晓,这些商家口碑爆棚!,樱花/紫薇/金叶复叶槭/红叶石楠/栾树/国槐/油松苗木批发基地供应商口碑排行 - 品牌推荐师
  • 揭秘Open-AutoGLM黑科技:如何用AI全自动操控安卓手机?
  • JUnit 5在现代测试覆盖率优化中的革命性实践
  • Ice:一款好用的MacOS状态菜单图标管理软件
  • Java调试器
  • 2025年知名的酚醛胶厂家推荐及采购参考 - 品牌宣传支持者
  • OpenAMP驱动开发:手把手教程(从零实现)
  • TensorBoard可视化全攻略:让TensorFlow训练过程一目了然
  • 时光胶囊:重温Windows XP的蓝色经典
  • 2025年靠谱的混凝土垫块/建筑水泥垫块厂家最新TOP实力排行 - 品牌宣传支持者
  • 5分钟掌握全国水系GIS数据:新手完整使用指南
  • 2025年评价高的hdpe缠绕管设备/缠绕管设备实力厂家TOP推荐榜 - 品牌宣传支持者
  • 如何极致释放AMD GPU潜力:xFormers在ROCm平台的性能调优完全指南
  • sceasy终极指南:单细胞数据格式转换的完整解决方案
  • 2025年热门的文创T恤定制/企业T恤定制厂家推荐及采购参考 - 品牌宣传支持者
  • ESP-IDF低功耗开发终极指南:从基础配置到深度优化的完整解决方案
  • 2025年中国汉堡加盟品牌年度排名:汉堡加盟品牌有哪些 - mypinpai