【C++】模板进阶--类模板特化

2023-11-15

这篇博客可参照我的上篇博客模板初阶 中讲的函数模板和类模板的内容,一起学习。

【本节内容】
非类型模板参数
类模板的特化

1.非类型模板参数

模板参数分 类型形参非类型形参
类型形参:出现在模板参数列表中,跟在class或typename之类的参数类型名称。
非类型形参:用常量做类(函数)模板的参数,在类(函数)模板中可将该参数当常量使用。

   //定义模板类型的静态数组
template <class T,size_t N=10>
  //其中,T是类型形参,N是非类型形参
class array
{
public:
	T&operator [](size_t index)
	{
		return _array[index];
	}
	size_t Size()const
	{
		return _size;
	}
	bool Empty()const
	{
		return 0 == _size;
	}
private:
	T _array[N];
	size_t _size;
};

注意:
1.浮点型、类对象以及字符串是不允许作为非类型模板参数的(一般都为int)。
2.非类型模板参数必须在编译器就能确定结果。

2.模板特化

2.1 概念:使用模板可以实现一些与类型无关的代码,但对于一些特殊类型可能会得到一些错误的结果。

例如:

template<class T>
bool IsEqual( T& left,T& right)
{
	return left == right;
}
void Test()
{
//char* p1 = "hello";	char* p2 = "hello";    //此时结果为相同,因为指向同一个地址
	char p1[] = "hello";
	char p2[] = "hello";
	if (IsEqual(p1, p2))
		cout << "相同" << endl;
	else
		cout << "不相同" << endl;
}

在这里插入图片描述
上面代码中,P1和P2的内容明明相同,为什么运行结果却是“不相同”呢?
其实啊,上面IsEqual 函数是直接按值比较,如果我们的参数是int或float类型当然是没有问题的,但是p1和p2是指针而不是各自的内容,这里就只能按指针的地址比较,因为P1和P2都是直接new出来的,所以在内存的位置肯定不相同,所以上面的结果是理所当然。
我们要想进行字符串的比较,就需要对模板进行特化。
模板特化:在原模板的基础上,针对特殊类型所进行特殊化的实现方式。
模板特化分为 函数模板特化和类模板特化

2.2 函数模板特化

函数模板特化的步骤:
1.必须要有一个基础的函数模板
2.关键字template后接一对空的尖括号<>
3.函数名后跟一对尖括号,<>中指定需要特化的类型
4.函数形参表:必须和函数模板的基础参数类型完全相同,若不同编译器会报错

//特化
template<>
bool IsEqual <char*> ( char*& left, char* & right)   //必须两个char
{
	return (strcmp(left, right) ==0);
}

也可以将函数直接给出。

bool IsEqual(char* left, char* right)
{
	return (strcmp(left, right) == 0);
}
2.3 类模板特化

2.3.1 全特化:将模板参数列表中所有的参数都确定化。

template<class T1,class T2>
class Date
{
public:
	Date()
	{
		cout << "Date<T1,T2>" << endl;
	}
private:
	T1 _d1;
	T2 _d2;
};
template<>
class Date<int,char>     //必须一个 int 一个char
{
public:
	Date()
	{
		cout << "Date<int,char>" << endl;
	}
private:
	int  _d1;
	char _d2;
};
void Test2()
{
	Date<int, int> d1;
	Date<int, char> d2;
}

2.3.2 偏特化:任何针对模板参数进一步进行条件限制设计的特化版本。
部分特化:将模板参数中的一部分参数特化

template<class T1>
class Date<T1,int >    //只要有一个int 就可以调用
{
public:
	Date()
	{
		cout << "Date<T1,int>" << endl;
	}
private:
		int  _d1;
		char _d2;
};

参数更进一步限制:针对模板更进一步的条件限制所设计的特化版本


//两个参数偏特化为指针类型
template<typename T1,typename T2>
class Date<T1*, T2*>    //只要指针就调用
{
public:
	Date() { cout << "Date<T1*,T2*>" << endl; }
private:
	T1 _d1;
	T2 _d2;
};

//两个参数偏特化为引用类型
template<typename T1, typename T2>
class Date<T1&, T2&>     //只要引用就调用
{
public:
	Date(const T1&d1, const T2&d2)
		:_d1(d1)
		, _d2(d2)
	{
		cout << "Date<T1&, T2&>" << endl;
	}
private:
	const T1& _d1;
	const T2& _d2;
};
类型萃取 typetraits
模板分离编译

什么是分离编译?
一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式。
模板的分离编译:
C/C++程序运行的步骤:

main.cpp
func.cpp
func.h

1)预处理:展开头文件、宏替换、条件编译(ifnef,define,endif)、去掉注释

main.i func.i

2)编译: 检查语法错误,生成汇编代码

main.s func.s

3)汇编:把二进制代码转换成二进制机器码

main.o func.o

4)链接:链接到一起,生成可执行代码(找函数的地址)

a.exe或a.out(默认名字)

一般在自己的程序得模板中不支持分离声明和定义,解决的方法是:
1.将声明和定义放在同一个头文件下(推荐)
a.hpp

//模板分离编译解决方法:声明和定义不分离
//.hpp 一般就表示声明和定义放在一起
template <class T>
T Add(const T&a, const T&b)
{
	return a + b;
}

main.cpp

int main()
{
 //链接时不用去call函数地址,因为汇编过程已经将此函数展开,可以直接使用
	cout << Add(1, 2) << endl;  
	system("pause");
	return 0;
}

2.模板定义的位置显式实例化(不实用)
a.h

//定义
template<class T>
T Add(const T&a, const T&b);
//分离编译解决方法:显式实例化
template
int Add(const int&a, const int&b);

a.cpp

//若不显式实例化则在编译时T无法生成确定类型,所以不生成对应汇编代码
template <class T>
T Add(const T&a, const T&b)
{
	return a + b;
}

main.cpp

int main()
{
	cout << Add(1, 2) << endl;   
	//发生错误原因:链接时才去call函数地址,但展开的.h中并没有生成可链接的汇编代码
	//解决方法的显式实例化使函数产生可用地址
	system("pause");
	return 0;
}
模板的总结

【优点】

  1. 模板复用了代码,节省资源,完成更快的迭代开发,C++的模板标准库STL(标准模板库)因此而产生
  2. 增强了代码的灵活性

【缺点】
1.模板会导致代码膨胀问题,也会使编译时间变长
2.出现模板编译错误时,错误信息凌乱,不宜定位错误
(模板类的成员函数都只按需实例化,未用到的函数不会主动进行实例化,所以模板类中的函数不宜一次发现错误,只有用到时才能看到。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【C++】模板进阶--类模板特化 的相关文章

  • Filter(过滤器)常见应用

    javaweb学习总结 四十六 Filter 过滤器 常见应用 一 统一全站字符编码 通过配置参数charset指明使用何种字符编码 以处理Html Form请求参数的中文问题 1 package me gacl web filter 2
  • 【深度学习】Faster R-CNN+win10+tensorflow1.12.0+python3.6+CUDA9.0+cudnn7.3配置

    Faster R CNN win10 tensorflow1 12 0 python3 6 CUDA9 0 cudnn7 3配置 一 源码下载 二 修改 lib 下部分文件 编译Cython模块 三 安装COCO API 四 下载数据 五
  • 【Leetcode】225. 用队列实现栈

    题目描述 请你仅使用两个队列实现一个后入先出 LIFO 的栈 并支持普通栈的全部四种操作 push top pop 和 empty 实现 MyStack 类 void push int x 将元素 x 压入栈顶 int pop 移除并返回栈
  • Selenium+Firefox的自动下载(去掉下载弹窗)

    Selenium Firefox的自动下载 去掉下载弹窗 一 去掉下载弹窗的优点 二 去掉下载弹窗的一般命令 三 重点 一 去掉下载弹窗的优点 检索键盘鼠标自动化控制模块的导入 可以无头化运行 不影响同时进行的其他的任务 二 去掉下载弹窗的
  • Apache Avro 文档概况

    文章主题来源于英文源文档 gt Apache Avro 1 11 0 文档 Apache Avro 1 11 0 Documentation 1 介绍 Apache Avro 是一个数据序列化 data serialization 框架 A

随机推荐

  • CentOS 7 下安装Chrome浏览器

    参考 http www cnblogs com hfyfpga p 6261819 html http blog csdn net johnnyhu90 article details 42127521 如果出现如下错误 curl 7 Fa
  • rust类型转换

    类型转换 类型转换分为隐式类型转换和显式类型转换 隐式类型转换是由编译器完成的 开发者并未参与 所有又称强制类型转换 显式类型转换是由开发者指定的 就是一般意义上的类型转换 一 显式转换 一 as 1 原生类型之间的转换 Rust不提供原生
  • OpenSSL SSL_read: Connection was reset, errno 10054

    一 问题描述 提交代码到github上 git报错如下 OpenSSL SSL read Connection was reset errno 10054 看报错提示 极大的可能是由于网络不稳定 连接超时导致的 如果多次尝试重新提交后 仍然
  • 解决:Cannot resolve plugin org.apache.maven.plugins:maven-compiler-plugin:3.1问题

    解决 Cannot resolve plugin org apache maven plugins maven compiler plugin 3 1问题 问题 Cannot resolve plugin org apache maven
  • 拳王虚拟项目公社:0基础小白副业年赚30W玩法大揭秘!看懂一半至少年赚10W!

    今天 我们分享一个励志的案例 一位工程师兼职创业 每天不超过3个小时 副业年收入30W 这个案例对我的触动和启发也非常大 我们主要分享 1 一类规模庞大的群体和一个小众冷门领域 他切下的蛋糕有多大 2 战术上的勤奋永远赚不了大钱 怎样的战略
  • C语言生成20个随机二位整数求奇偶个数并且从小到大输出

    这道题考察的是生成随机二位整数保存是要保存在一个容量为20的数组中 然后再循环进行判断奇偶性进行求个数和求和最终输出奇数平均值和偶数的和 最后采用冒泡排序对这个数组进行排序 冒泡排序可以看我之前的文章最终输出就行了 代码如下 include
  • 用MSYS2安装mingw

    文章目录 前言 卸载mingw 安装MSYS2 前言 安装MSYS2的原因是 在windows安装protobuf时 想用mingw编译protobuf的库 而protobuf的官方手册只给出一句 To build from source
  • IDEA常用快捷键

    Intellij IDEA常用快捷键 Ctrl E 显示最近修改的文件列表 Ctrl Shift Backspace Ctrl alt 左右方向键 跳转到上次编辑的地方 Ctrl F12 可以显示当前文件的结构 Ctrl Shift Ins
  • 【ICKIM 2022】第四届知识与信息管理国际会议

    2022 知识与信息管理国际会议 ICKIM 2022 第四届国际知识与信息管理会议 作为WSSE的研讨会 将于2022年9月28日至30日在厦门举行 一 会议出版 会议被接收的文章将出版到ACM 会议论文集 ISBN 978 1 4503
  • mybatis中的options注解

    mybatis的 Options注解能够设置缓存时间 能够为对象生成自增的key 场景 一个表id 主键 设置为自增 而当我们需要在dao层插入数据的时候立刻获取到该自动生成的id 实现 如下 Insert insert into inst
  • 内存检测工具Dr.Memory在Windows上的使用

    之前在https blog csdn net fengbingchun article details 51626705 中介绍过Dr Memory 那时在Windows上还不支持x64 最新的版本对x64已有了支持 这里再总结下 Dr M
  • 抽象工厂方法

    在工厂方法中 我们可以很方便的创建一个产品继承结构下的多个产品 那么考虑这么一种情况 我们需要在工厂中创建多个不同继承结构的产品 例如皮肤库 包含按钮 文本框 选择框等多个不同的元素 Spring皮肤库包含了一组相似的按钮 文本框 选择框
  • Window10手把手带你YOLOV5的火焰烟雾检测+tensorrt量化加速+C++动态库打包

    目录 0 引言 1 yolov5模型训练 1 2 模型训练 1 3 模型测试 2 模型转换 2 1 pt wts engine 2 1 1 pt转wts 2 1 2 wts转engine 3 动态库打包 0 引言 本人配置 win10 py
  • 简单实现点击el-tab-pane中的子组件按钮切换el-tabs

    简单实现点击el tab pane中的子组件按钮切换el tabs 实现效果 点击单条查看详细信息 实现跳转到详细信息面板 实现步骤 1 在父组件中声明函数 二 在要实现点击跳转的子组件中设置点击事件 主要的原理就是 tabs组件的面板激活
  • python笔记5-循环for和while

    1 for 获取列表中的项 for name in Christopher Susan print name name为变量 in后面的是循环列表 for会自动遍历列表 输出结果 Christopher Susan 指定循环次数 for i
  • WEB架构师成长之路之3:要懂哪些知识

    Web架构师究竟都要学些什么 具备哪些能力呢 先网上查查架构师的大概的定义 参见架构师修炼之道这篇文章 写的还不错 再查查公司招聘Web架构师的要求 总结起来大概有下面几点技能要求 一 架构师有优秀的编码能力 解决开发人员无法解决的难题 二
  • 伽罗华有限域的FEC

    FEC算法 cloudfly cn的博客 CSDN博客 fec算法 I 基于IP的语音和视频通话业务为了实时性 一般都是采用UDP进行传输 基站无线一般配置UM模式的RLC承载 因此丢包是不可避免的 在小区信号的边沿则丢包率会更高 为了通话
  • CloudCompare学习笔记(一)-- 界面初识

    本人也是cc纯小白 博客只用来记录学习内容和一些不懂的地方 如有错误还望指正 一 主界面 CC的界面大致可以分为以下几块 中间部分 1 DB Tree 打开的文件或者创建的实体都会存放在这里 2 Properties 选择的文件的属性 在打
  • c++函数为什么带imp_算法

    算法数学之美 日期 2018年1月13日 正文共 2779字3图 预计阅读时间 7分钟 来源 周平 最近网易云课堂开放了一节叫Linux内核分析的课程 一直对操作系统和计算机本质很感兴趣 于是进去看了下 才第一堂课 老师就要求学生写一篇关于
  • 【C++】模板进阶--类模板特化

    这篇博客可参照我的上篇博客模板初阶 中讲的函数模板和类模板的内容 一起学习 本节内容 非类型模板参数 类模板的特化 1 非类型模板参数 模板参数分 类型形参与非类型形参 类型形参 出现在模板参数列表中 跟在class或typename之类的