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

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

在这里插入图片描述


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

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


🎬 艾莉丝的简介:

在这里插入图片描述

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

在这里插入图片描述

文章目录


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

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

在这里插入图片描述

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

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

在这里插入图片描述


这个行,包括C++26都同步了,我们以后主要会看这个。

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

在这里插入图片描述


这个网站上面会有很多大佬,类似于论坛。


在这里插入图片描述

8 ~> 包装器

8.1 function

8.1.1 结构

template<classT>classfunction;// undefinedtemplate<classRet,class... Args>classfunction<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全解析|深入使用(附高频算法题详解)

在这里插入图片描述

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

classSolution{public:intevalRPN(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中的映射即可,算法实现如下所示——

classSolution{public:intevalRPN(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<classFn,class... Args>/* unspecified */bind(Fn&& fn, Args&&... args); with returntype(2)template<classRet,classFn,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_WARNINGS1#include<iostream>#include<vector>#include<functional>usingnamespace std;// ===================C++11:包装器=================//--------------------function---------------------intf(int a,int b){return a + b;}structFunctor{public:intoperator()(int a,int b){return a + b;}};classPlus{public:Plus(int n =10):_n(n){}staticintplusi(int a,int b){return a + b;}doubleplusd(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;intSub(int a,int b){return(a - b)*10;}intSubX(int a,int b,int c){return(a - b - c)*10;}intmain(){// 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, 10 function<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;return0;}// 运行结果:// 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表达式

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

Read more

Llama-2-7b在昇腾NPU上的六大核心场景性能基准报告

Llama-2-7b在昇腾NPU上的六大核心场景性能基准报告

引言 随着大语言模型(LLM)技术的飞速发展,其底层算力支撑硬件的重要性日益凸显。传统的GPU方案之外,以华为昇腾(Ascend)为代表的NPU(神经网络处理单元)正成为业界关注的焦点。为了全面、深入地评估昇腾NPU在实际LLM应用中的性能表现,我们进行了一项针对性的深度测评。本次测评选用业界广泛应用的开源模型Llama-2-7b,在 Atlas 800T A2 训练卡 平台上进行部署、测试与分析,旨在为开发者和决策者提供一份详实的核心性能数据、深度的场景性能剖析、以及可靠的硬件选型与部署策略参考。 模型资源链接:本项目测评使用的模型权重及相关资源可在 GitCode 社区获取:https://gitcode.com/NousResearch/Llama-2-7b-hf 一、 测评环境搭建与准备 扎实的前期准备是确保测评数据准确可靠的基石。本章节将详细记录从激活昇腾NPU计算环境到完成所有依赖库安装的全过程,确保测试流程的透明与可复现性。 1.1 激活NPU Notebook实例 我们通过GitCode平台进行本次操作。首先,需要进入项目环境并激活一个Notebook实例,这

By Ne0inhk
Midjourney官网地址是哪个?有没有中文官网?

Midjourney官网地址是哪个?有没有中文官网?

作为AI绘画领域的明星工具,Midjourney凭借其强大的图像生成能力风靡全球。许多用户初次接触时,最常问的问题便是:Midjourney的官网地址是什么?是否有中文官网? 一、Midjourney官网入口 Midjourney的唯一官方访问地址为: 👉 https://www.midjourney.com         需要注意的是,Midjourney的核心服务基于Discord平台运行。用户需先注册Discord账号,通过官网引导加入Midjourney频道,重要的是中文用户需要魔法才能使用官方MJ绘画功能。官网主要提供功能说明、订阅计划、作品展示等基础信息。 二、中文用户如何快速上手?         目前Midjourney尚未推出中文官网,且操作界面以英文为主。对于不熟悉Discord或英文界面的用户,可通过以下方式降低使用门槛: 1. 浏览器翻译插件(如谷歌翻译)辅助阅读 2. 参考中文社区教程(知乎、B站等平台有大量指南) 3. 使用第三方API服务——例如 OpenXS Midjourney API,提供全中文文档和本地化技术支

By Ne0inhk
[源力觉醒 创作者计划]_文心一言 4.5开源深度解析:性能狂飙 + 中文专精

[源力觉醒 创作者计划]_文心一言 4.5开源深度解析:性能狂飙 + 中文专精

文章目录 * [源力觉醒 创作者计划]_文心一言 4.5开源深度解析:性能狂飙 + 中文专精 * 一. 部署实战:单卡环境的极速落地 * 1.1 🖥️ 环境配置の手把手教程 📝 * 部署准备:硬件与镜像 * 依赖安装:一行代码搞定 * 1.2 🚀 模型启动の参数与验证 ✅. * 二. 多场景能力验证:从工业到学术 * 2.1 🏥 医疗影像诊断:从模糊影像到病灶定位 * 2.2 🚦 交通流优化:动态拥堵预测与策略设计 * 2.3 🔍 考古文本破译:甲骨文符号的跨学科解读 * 三. 性能优化与问题解决 * 3.1 🚀 性能优化策略:让模型跑得更快 * 3.2 🛠️ 常见错误解决方案 * 四. 与同类模型对比 * 🍬 核心优势对比🍭 * 🍬 对比结论🍭 * 五、

By Ne0inhk
Github Copilot Agent模式使用经验分享

Github Copilot Agent模式使用经验分享

本文总结了如何使用 GitHub Copilot Agent 模式,并分享实际操作经验。 前置设置 1. 使用 VSCode Insider; 2. 安装 GitHub Copilot(预览版)插件; 3. 选择 Claude 3.7 Sonnet(预览版)模型,该模型在代码编写方面表现出色,同时其它模型在速度、多模态(如图像识别)及推理能力上具备优势; 4. 工作模式选择 Agent。 操作步骤 1. 打开 “Copilot Edits” 选项卡; 2. 添加附件,如 “Codebase”、“Get Errors”、“Terminal Last Commands” 等; 3.

By Ne0inhk