C++模板特化

news2025/1/13 7:23:31

前言

模板特化对函数和函数都可以使用。它的作用是以某一模板函数或某个模板类为例,大部分情况下需要写的函数或内容是一致的,但是有些特别情况,所以我们需要单独拎出来。

模板参数

  • 模板参数可分为类型形参非类型形参
    类型形参: 出现在模板参数列表中,跟在class或typename关键字之后且class和typename可以混用。
  • 如下,是一个非类型模板参数的使用实例。这样传参使得更简洁的方式定义一个数组大小。
template<class T, size_t N> //N:非类型模板参数
class StaticArray
{
public:
	size_t arraysize()
	{
		return N;
	}
private:
	T _array[N]; //利用非类型模板参数指定静态数组的大小
};
  • 使用:
int main()
{
	StaticArray<int, 10> a1; //定义一个大小为10的静态数组
	cout << a1.arraysize() << endl; //10
	return 0;
}

注意:

  1. 非类型模板参数只能用整型类型。字符串、类对象、浮点数都不行。
  2. 非类型模板参数需要在编译阶段确认结果。即初始化时就给值。

模板特化

函数模板特化

  模板用在函数上使得多种类型的参数都能用同一种方式处理,但是存在某一些参数情况下需要用不同的处理方式,所以需要模板特化。
如下代码,普通数值类型能比较,但是字符串类型就比较不了,所以我们需要模板特化。

template<class T>
bool IsEqual(T x, T y)
{
	return x == y;
}
  • 函数模板特化的方式:
  1. 首先必须要有一个基础的函数模板。
  2. 关键字template<> 关键字template空的尖括号<>。
  3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型。
  4. 函数形参表必须要和模板函数的基础参数类型完全相同,否则不同的编译器可能会报一些奇怪的错误。

处理string类型的比较,需要按字典序比较,所以特化出能比较string类型的模板特化函数,函数特化代码如下:

//基础的函数模板
template<class T>
bool IsEqual(T x, T y)
{
	return x == y;
}
//对于char*类型的特化
template<>
bool IsEqual<char*>(char* x, char* y)
// 不写<char*>也可以
{
	return strcmp(x, y) == 0;
}

类模板的特化:

类模板特化分全特化和偏特化(半特化)。区别是全部特化和部分特化。

  • 全特化:
    有类模板代码如下:
template<class T1, class T2>
class Dragon
{
public:
	//构造函数
	Stu()
	{
		cout << "Stu<T1, T2>" << endl;
	}
private:
	T1 _D1;
	T2 _D2;
};

如果想对T1、T2是double和int时做特殊处理,则可写如下代码:

//对于T1是double,T2是int时进行特化
template<>
class Stu<double, int>
{
public:
	//构造函数
	Stu()
	{
		cout << "Stu<double, int>" << endl;
	}
private:
	double _D1;
	int _D2;
};
  • 调用:
Stu<int, double> s1; // 调用特化
Stu<int, int> s2; // 调用普通
  • 总结类全特化的写法:
  1. 要先写普通类模板。
  2. 写类前先加:template<>。
  3. 类名后跟一对尖括号,尖括号中指定需要特化的类型。
  • 半特化:参数更进一步限制。
    代码如下:我们对T1做限制
template<class T2>
class Dragon<double, T2>
{
public:
	//构造函数
	Stu()
	{
		cout << "Stu<double, T2>" << endl;
	}
private:
	double _D1;
	T2 _D2;
};
  • 总结偏特化的方式:
  1. template 偏特化类之前,先声明哪个参数不特化
  2. 类定义的<>中在适当位置加入类型
  • 参数更进一步的限制:偏特化不仅仅是特化部分参数,还可以根据模板参数比如使用T1、T2时候,我们限定传参为T1*、T2*时使用特殊化的类模板。
    代码如下:
//两个参数偏特化为指针类型
template<class T1, class T2>
class Stu<T1*, T2*>
{
public:
	//构造函数
	Stu()
	{
		cout << "Stu<T1*, T2*>" << endl;
	}
private:
	T1 _D1;
	T2 _D2;
};
//两个参数偏特化为引用类型
template<class T1, class T2>
class Stu<T1&, T2&>
{
public:
	//构造函数
	Dragon()
	{
		cout << "Stu<T1&, T2&>" << endl;
	}
private:
	T1 _D1;
	T2 _D2;
};

T1、T2同时为指针类型或为引用类型时,会分别调用两个特化类模板。

Stu<int, int> s1; // T1 T2
Stu<int*, int*> s2; // T1* T2*
Stu<int&, int&> s3; // T1& T2&

这里理解为,如果我们要特化关于指针或引用类型时,特化方式和普通默认类型稍有不一样,需要template<class T1, class T2>,全写出来,
class Stu<T1&, T2&>,类后的两个参数也全写出来,且涉及指针和引用类型算一种偏特化。

模板分离编译

  • (不是模板分离编译)分离编译指的是:一个程序(项目)由若干个源文件共同实现,每个源文件编译生成目标文件,最后将所有模板文件链接起形成单一可执行文件的过程叫分离编译,
  • 模板的分离编译:头文件只声明模板,而模板函数的实现在cpp。此外,任何程序都需要main.cpp(规范,当然放在某个别的cpp中也行)。如下图三部分:
    请添加图片描述
      使用这三个文件生成可执行文件,链接阶段会产生报错。
    回忆程序运行经过四个步骤:
  1. 预处理: 头文件展开、去注释、宏替换、条件编译等。
  2. 编译: 检查代码的规范性、是否有语法错误等,确定代码实际要做的工作,在检查无误后,将代码翻译成汇编语言。
  3. 汇编: 把编译阶段生成的文件转成目标文件。
  4. 链接: 将生成的各个目标文件进行链接,生成可执行文件。

因为上面三个被干成了两部分,没有连接起来。
模板分离编译失败的原因:
  在函数模板定义的地方(Add.cpp)没有进行实例化,而在需要实例化函数的地方(main.cpp)没有模板函数的定义,无法进行实例化。
所以:为什么在链接阶段错误?
  答:在链接时候main中调用的两个Add实际上没有被真正定义,main发现Add没有定义是因为cpp中的实现了的函数模板没有生成对应函数,因为没有做实例化,因为函数模板不知道T实例化为什么类型。

避坑方案

  1. 在模板定义时显示实例化,如下:不建议,用到一个类型就要实例化一个类型,干不完的
    请添加图片描述
  2. 将模板的声明和定义放一起。推荐

模板优缺点:

优点:灵活、复用简单,STL的重要工具。
缺点:代码膨胀、编译时间过长、报错信息难看、不容易定位。

题目

下列的模板声明中,其中几个是正确的( )

1)template

2)template<T1,T2>

3)template<class T1,T2>

4)template<class T1,class T2>

5)template<typename T1,T2>

6)template<typename T1,typename T2>

7)template<class T1,typename T2>

8)<typename T1,class T2>

9)template<typeaname T1, typename T2, size_t N>

10)template<typeaname T, size_t N=100, class _A=alloc<T>>

11)template<size_t N>

9、11中size_t N是非类型形参,9和11都是模板声明,关键点是跟在class和typename中即可。
共有:4\6\7\8\10\11共6个。

非模板的函数的调用优先级更高。

模板的编译:
模板不支持分离编译,分离后的模板实现需要自己写实例化,很麻烦。

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

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

相关文章

消息中间件(消息队列)

简介 MQ&#xff08;message queue&#xff09;消息队列&#xff0c;也叫消息中间件。消息队列已经逐渐成为企业IT系统内部通信的核心手段。它具有低耦合、可靠投递、广播、流量控制、最终一致性等一系列功能&#xff0c;成为异步RPC的主要手段之一。它是类似于数据库一样需要…

残差网络~

搬来这个 给自己学学啊,残差网络解决了什么&#xff0c;为什么有效 从深度神经网络的两大难题入手&#xff0c;说说残差网络的形式化定义与实现&#xff0c;并深入探讨其作用的机制&#xff0c;并结合文献对残差网络有效性进行了一些可能的解释。 残差网络是深度学习中的一个…

【论文阅读】(2020)Knapsack polytopes: a survey(下)

文章目录六、Valid inequalities, separation and computations 有效的不等式&#xff0c;分离和计算七、Complete linear descriptions of particular knapsack polytopes 特定背包多形体的完整线性描述7.1 Extended formulations7.2 Complete linear descriptions 完整的线性…

JavaFx TreeView TreeItem 设置额外属性

在使用JavaFx 编写GUI程序时&#xff0c;不可避免的需要创建一个树组件,下面是一个简单的树组件的代码。 import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.TreeItem; import javafx.scene.control.TreeView; import javafx.s…

clickhouse笔记05--快速部署3节点集群

clickhouse笔记05--快速部署3节点集群1 介绍2 方法步骤2.1 部署 zookeeper 集群2.2 拉起 clickhouse 集群2.3 测试集群3 注意事项4 说明1 介绍 clickhouse笔记01–快速部署clickhouse 介绍了如何快速部署单节点clickhouse服务&#xff0c;本文基于该博文继续介绍如何快速部署3…

Java进阶—JUC编程

1、线程和进程 获取CPU核数 /*** author java小豪* version 1.0.0* date 2022/12/15* description 测试*/ public class Test {public static void main(String[] args) {// 获取CPU核数// CPU 密集型&#xff0c;IO密集型System.out.println(Runtime.getRuntime().available…

响应式营销策划文化传媒公司网站模板源码

模板信息&#xff1a; 模板编号&#xff1a;8071 模板编码&#xff1a;UTF8 模板颜色&#xff1a;蓝色 模板分类&#xff1a;设计、广告、文化、影视 适合行业&#xff1a;影视传媒类企业 模板介绍&#xff1a; 本模板自带eyoucms内核&#xff0c;无需再下载eyou系统&#xf…

qt5实现pdf阅读器(三)——pdfjs

目录 1、参考 2、实现 3、开发记录 1、参考 使用Qt的WebEngine和javascript的pdf.js模块构建的PDF查看器。 参考链接1&#xff1a;GitHub - Archie3d/qpdf: PDF viewer widget for Qt 参考链接2&#xff1a;GitHub - yshurik/qpdfjs: Desktop PDF Viewer based on Qt and…

讯飞听见SaaS服务迈入全新时代

配图来自Canva可画 随着数字化时代的来临&#xff0c;国内各企业为了提升行业竞争力&#xff0c;纷纷开始利用数字化技术&#xff0c;来实现以降本增效为核心的数字化转型&#xff0c;得益于此&#xff0c;助力企业数字化转型升级的SaaS也开始进一步升温。 众所周知&#xff…

【代码审计-2】PHP框架MVC类文件上传断点测试挖掘

1.文件上传漏洞挖掘&#xff1a; (1)关键字搜索&#xff08;函数、键字、全局变量等&#xff09;&#xff1a;比如$_FILES&#xff0c;move_uploades_file等 (2)应该功能抓包&#xff1a;寻找任何可能存在上传的应用功能点&#xff0c;比如前台会员中心&#xff0c;后台新闻添…

电力系统两阶段随机优化(Matlab实现)

目录 目录 1 概述 2 单级随机优化算法 2.1 随机化-最小化 2.2 随机逐次凸近似 &#xff08;SCA&#xff09; 3 两级随机优化算法 3.1 批处理算法 3.2 在线算法 4 Matlab代码实现 1 概述 在与随机系统状态向量关联的两阶段随机优化问题中&#xff0c;优化变量分为两组…

Web前端105天-day32-HTML5_CORE

HTML5CORE02 目录 前言 一、复习 二、拖拽 三、上传服务器 四、Canvas 五、地图 总结 前言 HTML5CORE02学习开始 一、复习 跨域 浏览器的同源策略导致在网页中, 通过 AJAX 发送网络请求时, 默认只能向同源的服务器请求同源: 协议 端口号 域名 三者都相同产生跨域的原因…

RocketMQ疑难杂症之No route info of this topic解决方案

成因&#xff1a; 由于配置了 docker 虚拟 IP&#xff0c;导致 brocker 总是代理到 docker 的虚拟 IP 上。 原理&#xff1a; RocketMQ 的 broker 启动类 org.apache.rocketmq.broker.BrokerStartup 启动的时候会读取代码中的默认配置&#xff0c;关于 broker 的配置在 org.apa…

【关于时间序列的ML】项目 8 :使用 Facebook Prophet 模型预测股票价格

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

30.深度学习模型压缩方法-4

30.1 低秩分解 基于低秩分解的深度神经网络压缩与加速的核心思想是利用矩阵或张量分解技术估计并分解深度模型中的原始卷积核 卷积计算是整个卷积神经网络中计算复杂 度 最 高 的 计 算 操 作,通 过 分 解4D 卷积核张量,可以有效地减少模型内部的冗余性此外对于2D的全 连…

Hive+Spark离线数仓工业项目实战--项目介绍及环境构建(1)

项目简介 通过大数据技术架构&#xff0c;解决工业物联网制造行业的数据存储和分析、可视化、个性化推荐问题。一站制造项目主要基于Hive数仓分层来存储各个业务指标数据&#xff0c;基于sparkSQL做数据分析。核心业务涉及运营商、呼叫中心、工单、油站、仓储物料。 推荐教程…

DSP_TMS320F28377D_eCAP学习笔记

博主学习eCAP的使用主要是用于处理霍尔传感器&#xff0c;计算电机的电角度以及角速度。首先还是看了点哔哩哔哩的学习视频。 eCAP介绍 脉冲量的输入是在数字控制系统中最常见的一类输入量&#xff0c;控制器专门设置了脉冲捕获模块 (eCAP)来处理脉冲量&#xff0c;通过脉冲捕…

路由器的工作原理(计算机网络-网络层)

目录 路由器的构成 转发和路由选择的区别 典型的路由器结构 交换结构 输出端口 路由器与交换机的比较 两种基于存储转发的分组交换设备的比较 交换机和路由器各有的应用场合 三层交换机 三层交换机的应用 路由器的构成 路由器的任务 路由器是一种具有多个输入端口和多…

MT8385 Android AB分区系统升级(命令模式)

AB系统分区升级使用的是update_engine,RecoverySystem 只适用于单分区的系统升级 1.解压开update.zip 可以查看到palyload的属性 2.使用ADB命令update_engine_client即可对AB分区进行升级 使用adb shell 命令进行升级 update_engine_client --payload xxx --update --header…

【TypeScript】TS类型声明(二)

&#x1f431;个人主页&#xff1a;不叫猫先生 &#x1f64b;‍♂️作者简介&#xff1a;前端领域新星创作者、华为云享专家、阿里云专家博主&#xff0c;专注于前端各领域技术&#xff0c;共同学习共同进步&#xff0c;一起加油呀&#xff01; &#x1f4ab;系列专栏&#xff…