C++的模板(九):模板的实例化问题
前文子系统中的例子, SubSystem内部用了STL库的map模板:
template <class Event, class Response>
class SubSystem{
public:map<Event*, Response*> table;
public:void bind(Event *e, Response *r);void unbind(Event *e);
public:int OnMessage(Event *e);
};
而作为Key来使用的Event类型,就事论事而言,到这里只是一个整数数据的简单包装:
class Event {
public:int ev_id;~Event(){printf("~Event(id_%d)\n", ev_id);}
};
那么直接用Event类而不是用Event指针来构造map是不是更有效?确实。在不考虑将来有Event派生类的情况下,在这个例子可以这样改进。这样:
template <class Event, class Response>
class SubSystem{
public:map<Event, Response*> table;
public:void bind(Event *e, Response *r);void unbind(Event *e);
public:int OnMessage(Event *e);
};
同时,成员函数中指针的使用也要相应调整。这样SubSystem类就改完了。编译… 。预计直接通过,但编译报了很多错,刷了几屏都翻不过来… 。用过STL库工程师们都有过这种经验吧!
什么原因呢,STL中的容器,对用作key的类型是有些讲究的,key必须能够比较,而这里的Event类没写“operator<”运算。这就导致模板对key引用发生问题,模板内的一些函数或变量没法生成,发生雪崩效应,进而导致更多的引用错误报出来。编程中遇到这种情况,不用紧张,报的都是虚假的错误,只要找到模板的参数类,看看哪里没写完整,轻轻一改所有错误就会立即消失。
这里检查看到是Event类少了“operator<”运算符重载引起的问题。加上它就行了。几百个错误,两三句话就改完了:
class Event {
public:int ev_id;~Event(){printf("~Event(id_%d)\n", ev_id);}bool operator<(const Event &e) const { return ev_id<e.ev_id; }
};
当然这不是唯一的办法。如果不想改Event ,改less也可以。错误都是因为缺少“operator<”运算符,模板中的less实例化失败引起的。接着产生了连锁反应。直接把针对 Event的特殊的less加上就解决了问题。用less特化。因为less是std名称空间定义的模板,特化需要在同一名称空间进行:
class Event {
public:int ev_id;~Event(){printf("~Event(id_%d)\n", ev_id);}
};
namespace std{
template <>
struct less<Event> {bool operator()(const Event &e, const Event &e1) const {return e.ev_id<e1.ev_id;}
};
}
这样Event就不用改。或者,不从std名称空间改,重开一个less模板,如果参数类型是Event就特化,否则,就继承 std::less模板(是的,继承就不用写代码了),等等,都行:
namespace dts {
template <typename T>
struct less : std::less<T> {
};
template <>
struct less<Event> {bool operator()(const Event &e, const Event &e1) const {return e.ev_id<e1.ev_id;}
};
}template <class Event, class Response>
class SubSystem{
public:map<Event, Response*,dts::less<Event> > table;
public:void bind(Event *e, Response *r);void unbind(Event *e);
public:int OnMessage(Event *e);
};
map模板是可以重新设置less参数的。这样,问题就解决了。
另外,还有个更狠的办法,可以叫编译器立即闭嘴。向STL容器传入自定义类型的指针,而不是自定义类型本身。因为指针直接带有容器需要的所有运算符,这样编译器就再也不会报错了。
但这样容器的find函数也就不能再用了。恰好子系统的例子中就有一个这样的find,现在就来看看find:
Event *find(list<Event*> &l, Event &e)
{list<Event*>::iterator i;for(i=l.begin(); i!=l.end(); i++) {if ((*i)->ev_id==e.ev_id) return *i;}return 0;
}
list中存的是Event的指针,STL库的find需要相同的类型,也就是用Event的指针去找,如果找到,就给你一个你本来就已经有了的Event指针。看起来这像个悖论。但库的逻辑就是这样。所以子系统的例子就自己写了一个find。
如果不想自己写,还可以用STL库的find_if模板。它有个pred参数。这是重载了()运算符的仿函数。仿函数唯一的功能就是重载了()运算符。除此以外就是初始化。下面的Match就是仿函数,用来匹配find_if模板的pred参数:
struct Match {Event ev;bool operator()(Event* e) {return ev.ev_id==e->ev_id;}
};
Event *find(list<Event*> &l, Event &e)
{list<Event*>::iterator i;Match m;m.ev=e;i = std::find_if(l.begin(), l.end(), m);if(i!=l.end())return *i;return 0;
}
find_if的比较就很灵活了。但现在Match出现在全局名称空间。如果不想这个小不点污染名称空间,可以把它挪到任何一个关联的类里面去。而class Event看起来最合适。这就把它挪过去:
class Event {
public:int ev_id;~Event(){printf("~Event(id_%d)\n", ev_id);}struct Match {Event *ev;bool operator()(Event* e) {return ev->ev_id==e->ev_id;}};
};
看起来最合适,却需要改一改。因为放在这里 Event成了未定义完成的类, Match中不能直接用,所以改成用它的指针。相关代码也调整一下。这样就好了。
当然也可以向pred传入普通的比较函数,但find_if只向它传一个参数,另一个参数要自己想办法了:
Event *find(list<Event*> &l, Event &e)
{iterator i;static int ev_id;struct Match{static bool p(Event *e) {return ev_id==e->ev_id;}};ev_id=e.ev_id;i = std::find_if(l.begin(), l.end(), Match::p);if( i!=l.end()) return *i;return 0;
}
如果也不想用这种方法,还有没有别的办法?答案是,有的。最后还是可以回到STL的标准的find上来。直接用当然是不行,但是可以重载iterator迭代器:
class iterator: public list<Event*>::iterator{
public:Event& operator*() {return *(list<Event*>::iterator::operator*());}iterator &operator=(list<Event*>::iterator i) {list<Event*>::iterator::operator=(i);return *this;}
} ;Event *find(list<Event*> &l, Event &e)
{::iterator i, begin, end;begin= l.begin();end= l.end();i= std::find(begin, end, e);if(i!=end) return &*i;return 0;
}
iterator 这个名字跟std预定义的名字冲突了。所以用的时候带上了作用域分辨符,否则就不是这里的class iterator了。因为重载了*,return &*i; 意思就不是return i; 了。最后编译后报告Event类型少了个==运算,把它补上。这样也通过了。
相关文章:
C++的模板(九):模板的实例化问题
前文子系统中的例子, SubSystem内部用了STL库的map模板: template <class Event, class Response> class SubSystem{ public:map<Event*, Response*> table; public:void bind(Event *e, Response *r);void unbind(Event *e); public:int OnMessage(E…...
Clickhouse Projection
背景 Clickhouse一个视图本质还是表,只支持一种order By,不然要维护太多的视图。 物化视图能力有限。 在设计聚合功能时,考虑使用AggregatingMergeTree表引擎,现在有了projections,打算尝试使用一下 操作 ADD PROJE…...
放烟花短视频素材去哪里找?去哪里下载?烟花素材网分享
在当代社会,短视频凭借其独有的魅力成为大众传递情感、记录生活、分享快乐的新兴方式。特别是在庆祝节日和特殊时刻时,烟花的绚丽效果常常被用来吸引观众的目光,成为视频作品中的亮点。然而,对于短视频制作者来说,寻找…...
爬虫笔记14——爬取网页数据写入MongoDB数据库,以爱奇艺为例
下载MongoDB数据库 首先,需要下载MongoDB数据库,下载的话比较简单,直接去官网找到想要的版本下载即可,具体安装过程可以看这里。 pycharm下载pymongo库 pip install pymongo然后在在python程序中我们可以这样连接MongoDB数据库…...
Jenkins教程-10-发送飞书测试报告通知
上一小节我们学习了发送企业微信测试报告通知的方法,本小节我们讲解一下发送飞书测试报告通知的方法。 1、自动化用例执行完后,使用pytest_terminal_summary钩子函数收集测试结果,存入本地status.txt文件中,供Jenkins调用 conft…...
Swift开发——简单App设计
App的界面设计需要具有大量的图像并花费大量的时间,这样的应用不方便学习和交流,这里重点介绍SwiftUI界面元素的用法,通过简单App设计过程的讲解,展示图形用户界面应用程序的设计方法。 01、简单App设计 按照9.1节工程MyCh0901的创建方法,创建一个新的工程MyCh0902,此时工…...
Python操作mysql
一、python连接mysql 1.python连接mysql代码示例 from pymysql import Connection# 获取到mysql数据艰苦的连接对象 conn Connection(hostlocalhost,port3306,userroot,passwordroot ) # 打印mysql数据库软件信息 print(conn.get_server_info()) # 关闭到数据库的连接 conn.…...
监控易产品升级动态:V7.6.6.15版本全面升级
随着信息技术的不断发展,企业对系统监控和数据管理的需求日益增加。为了满足广大用户的实际需求,监控易团队经过不懈努力,成功推出了V7.6.6.15版本,对产品进行了全面升级和优化。本次升级不仅增强了产品的稳定性和可靠性ÿ…...
Vue3 + Element-plus + TS —— 动态表格自由编辑
前期回顾 《 穿越时空的代码、在回首:Evil.js两年后的全新解读 》-CSDN博客 Vue3 TS Element-Plus 封装Tree组件 《亲测可用》_ https://blog.csdn.net/m0_57904695/article/details/131664157?spm1001.2014.3001.5501 态表格 自由编辑 目录 ♻️ 效果图…...
虚拟机配置桥接模式
背景 因为要打一些awd比赛,一些扫描工具什么的,要用到kali,就想着换成一个桥接模式 但是我看网上的一些文章任然没弄好,遇到了一些问题 前置小问题 每次点开虚拟网络编辑器的时候都没有vmnet0,但是点击更改的时候却有vmnet0 第一步: 点击更改设置 第二步: 把wmnet0删掉 …...
星戈瑞DSPE-SS-PEG-CY7近红外花菁染料
DSPE-SS-PEG-CY7是一种具有复杂而精细结构的复合纳米材料,其在生物医学领域的应用增多。该材料结合了磷脂(DSPE)、聚乙二醇(PEG)、二硫键(SS)以及荧光染料(CY7)的特点&am…...
LeetCode:503. 下一个更大元素 II(Java 单调栈)
目录 503. 下一个更大元素 II 题目描述: 实现代码与解析: 单调栈 原理思路: 503. 下一个更大元素 II 题目描述: 给定一个循环数组 nums ( nums[nums.length - 1] 的下一个元素是 nums[0] )&…...
代码重构:解读重构概念及重构实战
目录 一.重构是什么(what) 1.重构的本质 2.重构≠性能优化 二.重构的目的(why) 1.去写好的代码 2.去写更灵活的代码 三.重构的时机(when and where) 1.何时重构 2.何时不重构 四.重构的方法(how) 1.重构关键核心 2.重构方法 3.重构工具 小结 一.重构是什么(what)…...
java.util.Optional类介绍
java.util.Optional 是 Java 8 引入的一个容器类,用于表示可能包含或不包含非空值的对象。它的设计初衷是为了减少程序中的空指针异常(NullPointerException),并使代码更加简洁和易读。 Optional 类的介绍 1. 特点 避免显式的 null 检查:使用 Optional 可以避免显式的 n…...
PhotoShop自动生成号码牌文件
1、说明 设计卡牌的时候,遇到自动生成编号,从01500到-02500,一个一个的手写,在存储保存成psd格式的文件,会很耗时。 下面将介绍如何使用ps自动生成psd格式的文件 2、使用excle生成数字 从01500到-02500 第一步&…...
02逻辑代数与硬件描述语言基础
2.1 逻辑代数(简单逻辑的运算) 2.2 逻辑函数的卡诺图(从图论的角度)化简法 2.3 硬件描述语言Verilog HDL基础(研究生阶段才用得到) 要求: 1、熟悉逻辑代数常用基本定律、恒等式和规则。 2、掌握…...
OpenGL3.3_C++_Windows(21)
抗锯齿 遇到模型边缘有锯齿:光栅器将顶点数据转化为片段的方式有关 抗锯齿:产生更平滑的边缘SSAA超采样抗锯齿:使用比正常分辨率更高的分辨率,来渲染场景,它也会带来很大的性能开销。 光栅器: 位于最终处…...
clickhouse学习
ClickHouse学习 安装部署 1.下载rpm文件 下载地址:https://packages.clickhouse.com/rpm/stable/ clickhouse-client-23.2.1.2537.x86_64.rpm clickhouse-common-static-23.2.1.2537.x86_64.rpm clickhouse-common-static-dbg-23.2.1.2537.x86_64.rpm clickhous…...
MySQL高级-索引-使用规则-前缀索引
文章目录 1、前缀索引2、前缀长度3、查询表数据4、查询表的记录总数5、计算并返回具有电子邮件地址(email)的用户的数量6、从tb_user表中计算并返回具有不同电子邮件地址的用户的数量7、计算唯一电子邮件地址(email)的比例相对于表…...
外星生命在地球的潜在存在:科学、哲学与社会的交织
外星生命在地球的潜在存在:科学、哲学与社会的交织 摘要:近年来,关于外星生命是否存在的讨论日益激烈。有研究表明,外星人可能已经在地球漫步,这一观点引发了广泛的科学、哲学和社会学思考。本文将从科学角度探讨外星…...
使用FRP 0.58版本进行内网穿透的详细教程
什么是FRP? FRP(Fast Reverse Proxy)是一款高性能的反向代理应用,主要用于内网穿透。通过FRP,您可以将内网服务暴露给外网用户,无需进行复杂的网络配置。 准备工作 服务器:一台具备公网IP的服…...
0000电子技术基础概述
数电 未来课的基础 以前是模块、器件级 现在是 系统级 价格、性能、 技术更新快速的好处:得到了实惠 坏处:工程师需要不断地学习,不变就容易out,要用发展的眼光看待问题 了解基础知识、还要有前沿概念。 理论课、实践课要相结…...
vscode+platformio使用STC官方库进行51单片机开发 -- 中断异常
问题描述 在进行STC8H1K08单片机的开发时,使用官方提供的C语言库函数,在vscodeplatformio开发环境下发现库函数的串口中断异常,看起来像是中断没有触发。 解决过程 用串口中断时一直没有触发中断,起初没有怀疑是中断的问题&…...
探索Android架构设计
Android 应用架构设计探索:MVC、MVP、MVVM和组件化 MVC、MVP和MVVM是常见的三种架构设计模式,当前MVP和MVVM的使用相对比较广泛,当然MVC也并没有过时之说。而所谓的组件化就是指将应用根据业务需求划分成各个模块来进行开发,每个…...
基于matlab的不同边缘检测算子的边缘检测
1 原理 1.1 边缘检测概述 边缘检测是图像处理和计算机视觉中的基本问题,其目的在于标识数字图像中亮度变化明显的点。这些变化通常反映了图像属性的重要事件和变化,如深度不连续、表面方向不连续、物质属性变化和场景照明变化等。边缘检测在特征提取中…...
CentOS安装ntp时间同步服务
CentOS安装ntp时间同步服务 安装ntp 检查服务器是否安装ntp: rpm -q ntp安装ntp: yum install -y ntp服务端配置 配置文件路径:/etc/ntp.conf 设置ntp为开机启动 systemctl enable ntpd查看ntp开机启动状态 enabled:开启, disabled:关闭 …...
【Linux进阶】UNIX体系结构分解——操作系统,内核,shell
1.什么是操作系统? 从严格意义上说,可将操作系统定义为一种软件,它控制计算机硬件资源,提供程序运行环境。我们通常将这种软件称为内核(kerel),因为它相对较小,而且位于环境的核心。 从广义上…...
PageOffice国产版在线编辑word文件
PageOffice国产版支持统信UOS、银河麒麟等国产操作系统。调用客户端WPS在线编辑word、excel、ppt等文件。在线编辑效果与本地WPS一致。如图所示: web系统集成pageofficeV6.0国产版的文档:PageOfficeV6.0国产版最简集成代码(Springboot) PageOffice最简集…...
Bitmap位图数据排列方式
读取dicom C# 使用fo-dicom操作dicom文件-CSDN博客 创建位图 通过读取dicom得到像素内存,本例单指彩色图像。 Bitmap dataBmp new Bitmap(imageWidth, imageHeight, stride, PixelFormat.Format24bppRgb, dstBmp); 当像素的内存按照RGB的排列模式时,…...
重磅消息:ONLYOFFICE8.1版本桌面编辑器发布:功能完善的 PDF 编辑器、幻灯片版式、改进从右至左显示、新的本地化选项等
目录 ONLYOFFICE介绍 PDF 编辑器 功能全面的 PDF 编辑器 文本编辑 页面处理 (添加、旋转、删除) 插入和调整各种对象,例如表格、形状、文本框、图像、TextArt、超链接、方程等。 此外 PDF 表单 文本文档编辑器更新内容 页面颜色 页面…...
yellow日本高清免费中文/点击宝seo
Excel可以获取多种数据库中的数据,在表的引用规则方面也存在一定的差异,在书写SQL查询语句时需要引起注意。下面将介绍几种常用表的引用方法。 1.Excel工作表引用规则 Excel工作表在引用时需要将其包含在方括号内“[]”,同时需要…...
移动端购物网站建设/免费网站seo优化
问题概述问题1:H5 web 移动端 输入框, 键盘唤起后fixed定位好的元素跟随页面滚动了起来… fixed属性失效了!满屏任性横飞, 如下图:问题2:有几后来含些在到气时按式近篇来又的方浏消风第三方输入法的ios机还会出现键盘弹出延迟,导致…...
辽宁省城乡建设网站/深圳网络营销策划公司
XML三种解析方式: SAX解析:基于事件驱动,事件机制基于回调函数的,得到节点和节点之间内容时也会回调事件 PULL解析:相同基于事件驱动,仅仅只是回调时是常量 DOM解析:是先把XML文件装入内存中。在…...
南宁网站开发外包报价/百度运营优化师
今天早上打开idea发现注册码过期了,网上搜索破解补丁时偶然发现了一个自定义idea主题的网站,试了下感觉很nice~、很beautiful~,记录一下以备今后更换使用^_^。 1.自定义主题样式网址:http://www.themesmap.com/ 2.使用说明&…...
怎么申请免费网址/国内好的seo
Javascript中总有一些所谓的细节知识会让你目瞪口呆。前段时间,项目组新增一个需要,要求系统中所有显示时间的地方支持日期格式可定制什么事日期格式可定制呢,在平常呢,我们看到的时间格式一般是“yyyy-MM-dd”形式的,…...
wordpress模板淘宝客模板/小说搜索风云榜
表面看起来,如今是以太坊的至暗时刻,而黎明前往往是最黑暗的。种种迹象表明,ETH 2.0 或许会成为以太坊下一个爆发点。文 | 秦晓峰 运营 | 盖遥 编辑 | 卢晓明出品 | Odaily星球日报(ID:o-daily)作为最早的…...