模板(二)

news2024/9/22 2:14:42

目录

非类型模板参数

引入

分类

使用typename的特殊情况

注意点 

模板特化

引入

介绍

函数模板特化 

使用

​编辑

优点

类模板特化 

全特化

偏特化

部分特化

特殊的特化 

使用

分离编译

介绍

问题代码示例 

代码

说明

预处理

编译

链接

类模板实例化原理

总结

解决方法 

显式实例化

声明和定义放在一个头文件


非类型模板参数

引入

一般我们使用模板都是想让这个类兼容更多的类型,但模板参数不止只有这个作用

分类

模板参数分为 类型形参 非类型形参
  • 类型形参 : 出现在模板参数列表中,跟在class或者typename之后的参数类型名称(这两个一般情况下可以随意使用,但在某些情况下只能使用typename)
  • 非类型形参 : 就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用(eg: 定义数组大小)

使用typename的特殊情况

  • 当我们需要使用一个类里的类型时, 就得使用::来指明该类型所属的类名
  • 但在编译期间,编译器是不知道这个东西到底是一个类型,还是一个静态成员变量(根据语法来说,静态成员变量也可以被这样调用)
  • 如果这里是变量,我们用变量作为类型来创建变量,那语法就错误了
  • 而这里仅仅只是类名,并没有实例化,编译器无法通过代码判断是否合规(没有实例化就找不到对应的代码)
  • 所以为了安抚(?)编译器,需要在类名的前面 + typename,来告诉编译器,这里是一个类型,不要觉得有语法错误 ,具体等实例化后去类里找就行

注意点 

  1. 浮点数、类对象以及字符串 " 是不允许作为非类型模板参数的,只能是整型(最初创造出来就是为了处理大小啥的)
  2. 非类型的模板参数必须在编译期就能确认结果,C++的模板机制要求 -- 编译器在编译期间就生成模板的实例化代码,而这些代码的生成需要基于已知的、在编译期就可以确定的参数值

模板特化

引入

之前在优先级队列中,我们有使用仿函数实现比较函数

当时如果传入参数是自定义类型时,需要我们另写一种比较函数,但也可以采用另外一种方法 -- 函数模板特化

介绍

特化是在原模板类的基础上,针对特殊类型 所进行特殊化的实现方式
模板特化分为 -- 函数模板特化 与 类模板特化

函数模板特化 

使用

 

 在需要特化的函数名后 + <特化的类型>,这样这里就不需要T类型,但仍需要写tmplate<>

优点

按照原先的方法,直接给出对应函数,那么可能在传参的时候就费劲点,可能需要把所有参数都给出

但如果有函数特化,就不需要传入后两个参数,直接传类型就够了(因为此时函数名仍是当时给出的缺省参数)

类模板特化 

写法是一样的,只不过针对的对象不一样,一个是函数,一个是类

全特化

将类的所有模板参数都进行特化(都给出具体类型)

偏特化

部分特化

将模板参数类表中的一部分参数特化

特殊的特化 

可以将普通类型特化成该类型的指针/引用版本

使用

之前这样的类无法将自定义类型的指针传入进行比较(因为我们要的是比较对象),所以我们是另写了一个新类来完成该功能

但现在我们也可以使用特化的方式来实现

分离编译

介绍

分离编译是一种编程技术,允许将程序代码分割成多个文件,每个文件可以独立地编译成目标文件(.o文件),然后将这些目标文件链接在一起, 来创建最终的可执行程序

分离编译的核心思想 -- 是将代码逻辑分解为多个独立的模块,每个模块可以单独编译,从而减少了重新编译整个项目的需要 

问题代码示例 

一般来说,分离编译虽然很方便,但也很容易出现不少问题

代码

比如下面的三个文件

stack.h:

 stack.cpp:

main.cpp:

说明

预处理

在这三个文件形成可执行文件的过程中,首先是在两个cpp文件中,将.h文件展开... ,形成.i文件

编译

  • 这样stack.i中,有stack类的声明和定义,还有A类的func1定义 ; 但main.i中只有stack类的所有声明+部分定义 , 和A类的所有声明
  • 所以在编译阶段,只能确定 main.i中的size(),以及stack类的构造函数 的地址(这里只是生成了与地址相关的信息,但这些信息还没有映射到最终的绝对地址 , 编译阶段的地址是为后续阶段提供信息的一种中间状态)
  • 以及生成修饰后的函数名
  • 虽然没有确定所有函数的地址,但是编译是可以通过的,因为含有对应函数的声明

接下来生成.o文件

上面这三个阶段,对应生成地址的情况如下图:

链接

  • 接下来就是进行链接,链接是可以将func1的地址确定的,因为func1的定义有在stack.cpp中,俩文件相互一交流(拿着修饰后的函数去符号表找),就可以确定辽
  • 但素,这样的代码会报错,编译器说push在链接中出现问题
  • 原因是在main.s中,push修饰后的函数名适合int有关的(因为实例化传入的类型就是int),但是在stack.s中,没有人告诉他要实例化成什么,所以并没有实际生成代码,只是一个壳子,也就没有什么地址,自然在符号表中找不着

类模板实例化原理

  • 编译器在遇到类模板的使用时,会生成一个用于在实际需要时实例化代码的计划,这个计划称为模板的实例化
  • 这个计划会记录下特定模板参数,以及生成实际代码的需要
  • 在源文件中使用模板时,需要提供模板参数,并创建一个模板的实例 , 这样就会告诉编译器 我们想要使用特定类型来实例化模板
  • 当编译器在编译源文件时,会根据计划生成 特定类型的类代码,其中包含了特定类型的成员函数和数据成员

总结

所以,上面的情况之所以出现问题,就是因为类的具体代码不在当前编译单元中

编译器需要生成实际的代码,但如果实际的代码在其他源文件中,链接器就无法找到这些代码,从而导致链接错误

解决方法 

显式实例化

如果一定要把类的声明和定义放在两个文件,可以采用显式实例化模板的方式

但是坏处就是,一旦使用新的类型实例化模板,就得加代码,hin麻烦

声明和定义放在一个头文件

这样在包括头文件的源文件中,一旦源文件实例化了类,就能及时的在编译过程生成实际代码,然后可以链接成功

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

单片机TVS/ESD二极管防护

TVS 瞬态电压抑制二极管Transient Voltage Suppressor ESD 静电释放二极管 Electro-Static discharge 这两种本质上都是二极管。都是利用了二极管正向导通、反向截止的特性。二极管在反向截止截止条件下&#xff0c;如果电压继续增大&#xff0c;将会引发雪崩&#xff0c;使得…

【C语言基础】牛客题库练习第(一)期

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…

解决MASM32代码汇编出错: error A2181: initializer must be a string or single item

最近用MASM32编程更新SysInfo&#xff0c;增加对IPv6连接信息的收集&#xff0c;使用到了 typedef struct _MIB_TCP6ROW_OWNER_MODULE {UCHAR ucLocalAddr[16];DWORD dwLocalScopeId;DWORD dwLocalPort;UCHAR ucRemoteAddr[16];DWORD …

Visual Studio 2017安装和项目配置

目录 前言1. What、Why and How1.1 What1.2 Why1.3 How 2. 安装3. 创建新项目4. 配置OpenCV库4.1 下载opencv安装包4.2 配置系统环境变量4.3 VS项目环境配置4.4 总结 5. 已有项目添加6. Tips6.1 常用快捷键6.2 字体和颜色选择6.3 配置编译路径 结语下载链接参考 前言 最近因为项…

操作系统期末复习合集——第六章:文件管理

操作系统期末复习合集——第六章&#xff1a;文件管理 引言6.1 文件和文件系统一、文件1. 有结构文件2. 无结构文件&#xff08;流式文件&#xff09; 二、文件系统1. 功能2. 文件系统接口 6.2 文件的逻辑结构一、文件结构二、文件逻辑结构的类型三、顺序文件1. 排序2. 读/写3.…

Java后端开发面试题——集合篇

ArrayList底层的实现原理是什么 底层数据结构 ArrayList底层是用动态的数组实现的 初始容量 ArrayList初始容量为0&#xff0c;当第一次添加数据的时候才会初始化容量为10 扩容逻辑 ArrayList在进行扩容的时候是原来容量的1.5倍&#xff0c;每次扩容都需要拷贝数组 添加逻…

最强嘴提o.o文字转语音

下载 链接&#xff1a;https://pan.baidu.com/s/1cb24WW2dihtRpMz4giMxyw 提取码&#xff1a;k3xu 解压密码&#xff1a;领航员未鸟 项目源码&#xff1a;https://github.com/Plachtaa/VITS-fast-fine-tuning/tree/main 使用 解压后来到&#xff0c;该目录下&#xff0c;把…

在云原生环境中构建可扩展的大数据平台:方法和策略

文章目录 1. **选择适当的云提供商&#xff1a;**2. **采用容器化和微服务架构&#xff1a;**3. **分层架构设计&#xff1a;**4. **弹性计算资源&#xff1a;**5. **使用分布式计算框架&#xff1a;**6. **数据分区和分片&#xff1a;**7. **使用列式存储&#xff1a;**8. **缓…

JS 常见的 6 种继承方式

原型链继承 原型链继承是比较常见的继承方式之一&#xff0c;其中涉及的构造函数、原型和实例&#xff0c;三者之间存在着一定的关系&#xff0c;即每一个构造函数都有一个原型对象&#xff0c;原型对象又包含一个指向构造函数的指针&#xff0c;而实例则包含一个原型对象的指…

On-Manifold Optimization: Local Parameterization

Overview Manifold Space vs Tangent Space Jacobian w.r.t Error State Jacobian w.r.t Error State vs True State According 1 2.4, The idea is that for a x ∈ N x \in N x∈N the function g ( δ ) : f ( x ⊞ δ ) g(\delta) : f (x \boxplus \delta) g(δ):f(x…

<C++> STL_deque

<c> STL_deque 1.deque的使用 deque(双端队列)&#xff1a;是一种双开口的"连续"空间的数据结构&#xff0c;双开口的含义是&#xff1a;可以在头尾两端进行插入和 删除操作&#xff0c;且时间复杂度为O(1)&#xff0c;与vector比较&#xff0c;头插效率高&a…

字节码操作的手术刀-Javassist

Javassist 前面文章介绍的 ASM 入门门槛还是挺高的&#xff0c;需要跟底层的字节码指令打交道&#xff0c;优点是小巧、性能好。Javassist 是一个性能比 ASM 稍差但是使用起来简单很多的字节码操作库&#xff0c;不需要了解字节码指令&#xff0c;由东京工业大学的数学和计算机…

求解整数规划问题的割平面法和分支定界法

文章目录 整数规划割平面法分支定界法代码实现 整数规划 整数规划问题是优化变量必须取整数值的线性或非线性规划问题&#xff0c;不过&#xff0c;在大多数情况下&#xff0c;整数规划问题指的是整数线性规划问题。 其数学模型为 m i n f ( x ) c T x s.t A x b x ≥ 0 x…

opencv的haarcascade_frontalface_default.xml等文件

文章目录 GitHub下载在安装好的OpenCV文件夹下寻找opencv-python中获取 GitHub下载 下载地址&#xff1a;https://github.com/opencv/opencv/tree/master/data/haarcascades 在安装好的OpenCV文件夹下寻找 路径如下&#xff1a; 你安装的opencv路径\OpenCV\opencv\build\et…

亮点!视频云存储/安防监控视频智能分析平台睡岗离岗检测

在生产过程中&#xff0c;未经领导允许的擅自离岗、睡岗会带来很多的潜在危害。TSINGSEE青犀推出的视频云存储/安防监控视频智能分析平台得睡岗离岗检测根据AI视频分析技术建立人工智能算法&#xff0c;对视频画面展开分析与识别。自动识别出人员睡岗、离岗、玩手机与抽烟等动作…

十六、pikachu之SSRF

文章目录 1、SSRF概述2、SSRF&#xff08;URL&#xff09;3、SSRF&#xff08;file_get_content&#xff09; 1、SSRF概述 SSRF(Server-Side Request Forgery&#xff1a;服务器端请求伪造)&#xff1a;其形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能&…

c++ qt--线程(一)(第八部分)

c qt–线程&#xff08;一&#xff09;&#xff08;第八部分&#xff09; 一.进程&#xff08;Process&#xff09; 在任务管理器中的进程页下&#xff0c;可以看到进程&#xff0c;任务管理器将进程分为了三类&#xff0c;应用、后台进程、window进程 应用&#xff1a; 打开…

MyBatis-Plus 总结

MyBatis-Plus简介 官网&#xff1a;https://baomidou.com/ GitHub&#xff1a;https://github.com/baomidou/mybatis-plus Gitee&#xff1a;https://gitee.com/baomidou/mybatis-plus 简介 MyBatis-Plus &#xff08;简称 MP&#xff09;是一个 MyBatis的增强工具&#x…

【C++入门到精通】C++入门 —— 多态(抽象类和虚函数的魅力)

阅读导航 前言一、多态的概念1. 概念2. 多态的特点 二、多态的定义及实现1. 多态的构成条件2. 虚函数3. 虚函数的重写⭕虚函数重写的两个例外1.协变(基类与派生类虚函数返回值类型不同)2.析构函数的重写(基类与派生类析构函数的名字不同) 4. override 和 final&#xff08;C11 …

SLAM从入门到精通(开始篇)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 很多同学喜欢学习linux&#xff0c;但是他们只是把linux当成是一个嵌入式技术在学习&#xff0c;而不是当成工具在使用。平时&#xff0c;要么是自…