c++:模板进阶

1.非类型模板参数

我们之前的模板参数是类型模板参数,而非类型模板参数是常量,和宏功能类似

但是宏有个缺点,因为同一个宏的常量在一个项目中只有一个值,所以不能满足更加灵活多变的项目需求,但是非类型模板参数就可以通过输入不同的参数解决这个问题


比如我们需要使用一个函数去计算物体落下所需时间,那么就需要一个重力加速度g

粗略计算就是10,在月球上又会再变小。

因为我们的常量会在不同的情景下发生变化,所以我们要求这个常量的改变是简单的,而非类型模板参数刚好可以解决这个问题

注意:当前c++只支持整形,double类型等其他类型都不行

2.模板的特化

一般情况下模板可以很好解决各种数据类型的问题,但是如果遇到一些特殊的数据类型就会导致出现逻辑问题。

比如对于整形,浮点型等数据类型的比较,直接用大于小于符号就可以进行比较,但是如果遇到整形指针,我们想比较的是指针指向的整形数据,而不是指针本身。此时如果还是直接使用大于小于符号比较就会出问题

这里我们的lessfun函数就是对数据直接比较,整形的数据比较没有问题,但是对于指针类型的比较就会出问题,我们想比的是nn1指向的1,nn2指向的2,而不是指针本身

2.1函数模板特化

接下来我们实现函数模板的特化解决这个问题我们这里就把lessfuc关于int*类型的情况特化处理了,这样子在使用lessfuc函数遇到int*类型时就不会使用指针直接比较大小,而是进入这个特化的模板进行解引用的比较

函数模板的步骤:
1.有一个正常的非特化函数模板,然后在这个模板的基础上再进行特化修改

2.将模板的尖括号置空,然后把需要特化的类型用尖括号写在特化模板函数名的后面

3.修改数据类型为特化类型

4.函数参数的关系必须和模板函数一样,否则会出问题

eg:

这里我们如果直接原封不动的替换类型会报错,究其原因是修饰的关系错了

模板中const修饰的是变量本身,而特化模板中修饰的是变量指向的内容

我们将const的位置改动到*右边即可


实际上我们如果需要对某种特定类型使用特殊逻辑,我们会使用普通函数,而不是特化模板。因为使用函数的时候优先级更高的是匹配度,匹配度一样就使用已经存在的函数

由于函数可以利用参数自动匹配,而不是必须显式实例化,所以这个写法也可以实现和函数模板特化一样的功能

2.2类模板特化

(1)全特化:将类的所有模板参数都特化

特化的步骤与函数模板一样

我们给lessfuc类(仿函数)关于int*特化之后,就可以实现int指针指向的内容的正确比较大小判断了

(2)偏特化:将类的部分模板参数特化

原模板类:

第一种:特化出具体类型

特化步骤:

1.将需要特化的模板参数从类模板中删除,然后在类名中用尖括号包含不用特化的类型和需要特化的具体类型

2.修改类中特化的类型

我们把T2特化为int类型,而没有特化T1。

第二种:不特化出具体类型,改变模板类型

特化步骤:
1.在类名中用尖括号包含需要改成的模板类型

2.若有需要,改变类中对应类型参数的顺序


总结:我们函数就可以不使用模板特化,而是写一个普通函数

对于类,我们需要写特化模板

3.模板分离编译

分离编译:

项目中若干个源文件共同运行,各个源文件单独编译生成目标文件最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式

具体过程:
1.(分别进行)预处理:注释删除,展开头文件,宏替换

文件从,cpp或.h变成.i文件

2.(分别进行)编译:检查语法正确性,将代码转换成汇编代码

文件从.i变成.s

在这个过程中函数内部代码就变成一个个汇编指令,并存储在一段连续地址中,而调用函数的本质就是call(跳转),跳转就需要知道函数此时的地址。

若跳转的函数在同一个文件且在该函数之前出现,那么可以直接call一个具体的地址。

若出现在该函数后面,或者不在同一个文件中,那么他的编译虽然可以通过,不过call的就是一个“ ?”,而不是一个具体的函数地址。这相当于我们给编译器一个承诺,承诺我们有这样一个函数,后面的过程我们才会兑现这个承诺,把地址给到call。

3.(分别进行)汇编:将汇编代码转成二进制机器码

生成目标文件.o

在这个过程中会有一个符号表负责记录函数的地址,方便后续的链接过程查找函数地址

4.(一起进行)链接:合并成可执行程序,链接函数地址

生成可执行程序.exe

特殊情况:出现模板函数且模板函数声明和定义分离

模板函数距离编译还差一个实例化,而有定义的部分不知道用什么类型实例化,所以既没有编译也没有进入符号表。有声明的地方知道用什么类型实例化,编译器先让他过了,到了链接部分由于该函数没有编译,所以找不到地址,就报错了

解决方法:

方法一:显示实例化

显示实例化可以让模板进行编译并进入符号表,从而链接部分就可以跳转到函数所在位置

方法二:将定义与声明写在同一个头文件

如果代码量不大就直接声明和定义一起写了,代码量较大就把定义写在同一个头文件即可。

进行这个操作后我们在.cpp文件中直接就可以call到地址,链接部分不用再找地址了

4.总结

优点远大于缺点

优点:

1.代码兼容性更高,更灵活

2.复用代码节省资源

缺点:

代码膨胀,编译时间变长。

出现模板错误报错信息混乱,难以定位

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/21478.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java 集合数据处理技巧:使用 Stream API 实现多种操作

​ 在 Java 开发中,对集合数据进行处理是非常常见的需求,例如去重、排序、分组、求和等。Java 8 引入的 Stream API 为我们提供了一种简洁、高效的方式来处理集合数据。本文将详细介绍如何使用 Stream API 实现多种集合数据处理操作,并给出相…

计算机网络基础杂谈(局域网、ip、子网掩码、网关、DNS)

目录 1. 简单局域网的构成 2. IP 地址 3. 子网掩码 4. IP地址详解自定义IP 5. IP 地址详解 6. 网关 7. DNS 域名解析 8. ping 1. 简单局域网的构成 交换机是组建局域网最重要的设备,换句话说,没有交换机就没法搭建局域网 交换机不能让局域网连…

基于SpringBoot的高校教学资料管理系统的设计与实现(源码+SQL脚本+LW+部署讲解等)

专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌。 技术范围:SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:…

Rust 未来会成为主流的编程语言吗?

Rust是由Mozilla团队主导开发的编程语言,首次亮相是在2010年。自发布以来,Rust凭借其内存安全性、出色的性能和对并发操作的支持,逐渐吸引了众多开发者的关注。据Stack Overflow的2021年调查数据显示,Rust连续多年被开发者评为最喜…

【Java】代理模式

代理模式 代理模式是指给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问 代理模式是一种结构型设计模式 背景 如果不采用代理,对一个类的多个方法进行监控时,重复的代码总是重复出现,不但破坏了原方法,…

STM32 看门狗

目录 背景 独立看门狗(IWDG) 寄存器访问保护 窗口看门狗(WWDG) 程序 独立看门狗 设置独立看门狗程序 第一步、使能对独立看门狗寄存器的写操作 第二步、设置预分频和重装载值 第三步、喂狗 第四步、使能独立看门狗 喂狗…

LLM论文笔记 15: Transformers Can Achieve Length Generalization But Not Robustly

Arxiv日期:2024.2.14机构:Google DeepMind / University of Toronto 关键词 长度泛化位置编码数据格式 核心结论 1. 实验结论:十进制加法任务上的长度泛化最佳组合: FIRE位置编码 随机化位置编码 反向数据格式 索引提示&…

超详细!一文搞定PID!嵌入式STM32-PID位置环和速度环

本文目录 一、知识点1. PID是什么?2. 积分限幅--用于限制无限累加的积分项3. 输出值限幅--用于任何pid的输出4. PID工程 二、各类PID1. 位置式PID(用于位置环)(1)公式(2)代码使用代码 2. 增量式…

【Linux探索学习】第二十八弹——信号(下):信号在内核中的处理及信号捕捉详解

Linux学习笔记: https://blog.csdn.net/2301_80220607/category_12805278.html?spm1001.2014.3001.5482 前言: 在前面我们已经学习了有关信号的一些基本的知识点,包括:信号的概念、信号产生和信号处理等,今天我们重…

Qt中使用QPdfWriter类结合QPainter类绘制并输出PDF文件

一.类的介绍 1.QPdfWriter介绍 Qt中提供了一个直接可以处理PDF的类,这就是QPdfWriter类。 (1)PDF文件生成 支持创建新的PDF文件或覆盖已有文件,通过构造函数直接绑定文件路径或QFile对象; 默认生成矢量图形PDF&#…

快速上手gdb/cgdb

Linux调试器-gdb使用 1.背景2.调试原理、技巧命令2.1指令2.2 本质2.3 技巧 1.背景 程序的发布方式有两种,debug模式和release模式 Linux gcc/g出来的二进制程序,默认是release模式 要使用gdb调试,必须在源代码生成二进制程序的时候, 加上 -g…

linux网络编程(1.5w字+内部程序理解网络)

目录 核心大图: 网络字节序 网络字节序与主机字节序 地址转换函数 一、inet_ntoa函数 二、inet_aton函数 三、inet_aton和inet_ntoa的测试 in_addr转字符串的函数: socket编程接口 socket 常见API 1.socket 参数1:int af 参数2:…

windows环境下用docker搭建php开发环境dnmp

安装WSL WSL即Linux子系统,比虚拟机占用资源少,安装的前提是系统必须是win10以上。 WSL的安装比较简单,网上有很多教程,例如:WSL简介与安装流程(Windows 下的 Linux 子系统)_wsl安装-CSDN博客&…

Nginx之rewrite重写功能

目录 一、rewrite概述 1、rewrite功能 2、跳转场景 二、标准配置指令 1、rewrite日志记录指令 2、未初始化变量告警日志记录指令 3、rewrite 指令 3.1 正则表达式 三、rewrite模块使用实例 1.基于域名的跳转 2.基于客户端 IP 访问跳转 3.?基于旧域名跳转到新域名后…

Mybatis(一)

配置文件 必要的用户密码要修改, 还有绿色线的名字要修改成数据库的 配置文件直接cv 创建 复习之前的知识进行分层处理 与前面一一对应, 后面三个发现后面输出是null, 没有一一对应, 后面再解释解决方法 运行发现, 输出正常 idea的测试类 两个注解了解 记得加上这个, 不然无…

一周学会Flask3 Python Web开发-http响应状态码

锋哥原创的Flask3 Python Web开发 Flask3视频教程: 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 在Flask程序中,客户端发出的请求触发相应的视图函数,获取返回值会作为响应的主体,最后生成…

七星棋牌源码高阶技术指南:6端互通、200+子游戏玩法深度剖析与企业级搭建实战(完全开源)

在棋牌游戏行业高速发展的今天,如何构建一个具备高并发、强稳定性与多功能支持的棋牌游戏系统成为众多开发者和运营团队关注的焦点。七星棋牌全开源修复版源码 凭借其 六端互通、200子游戏玩法、多省区本地化支持,以及 乐豆系统、防沉迷、比赛场、AI智能…

C++和OpenGL实现3D游戏编程【总览】

欢迎来到zhooyu的游戏专栏。 主页网址:【zhooyu】 专栏网址:【C和OpenGL实现3D游戏编程】 🌟🌟🌟这里将通过一个OpenGL实现3D游戏编程实例教程,带大家深入学习OpenGL知识。知识无穷而人力有穷,…

pycharm社区版有个window和arm64版本,到底下载哪一个?还有pycharm官网

首先pycharm官网是这一个。我是在2025年2月16日9:57进入的网站。如果网站还没有更新的话,那么就往下滑一下找到 community Edition,这个就是社区版了免费的。PyCharm:适用于数据科学和 Web 开发的 Python IDE 适用于数据科学和 Web 开发的 Python IDE&am…

GPT-Sovits:语音克隆训练-遇坑解决

前言 本来以为3050完全无法执行GPT-Sovits训练的,但经过实践发现其实是可以,并且仅花费了十数分钟便成功训练和推理验证了自己的语音模型。 官方笔记:GPT-SoVITS指南 语雀 项目地址:https://github.com/RVC-Boss/GPT-SoVITS 本人…