前言:
C++ 中的模板是一个强大的功能,允许程序员编写通用的代码,这些代码可以处理任何数据类型。模板使得代码更加灵活和可重用,而不必为每种数据类型编写重复的代码。下面详细解释 C++ 中的模板
内容摘要:
本文内容包含最基本的函数模板和类模板的基础认识和使用,然后通过另一个角度,从函数模板的特化方面,介绍了函数模板的特化和类模板的特化,分析了模板为什么一般不能通过分离编译实现的原理,最后将模板的优劣势进行总结。
函数模板
在C语言中,我们要实现一个两数之和,当我们是实现出一个整数的加法函数进行两个整数的加法,当我们又有需求进行含有小数的数据运算时,浮点数进行隐式类型转换调用我们写的那个整形的加法函数,最后运算出来的结果会造成精度的丢失,要想进行精度的保留,我们又需要重新写一个结构一模一样的函数,只是数据的类型发生了改变,这就让人很难受,因此C++ 中提出泛型编程的概念,通过函数模板可以完美解决问题。
函数模板的格式
关键字template + <class/typname T>
这里class和typname是等价的 这里模板参数可以用任意字母 一般用T
通过关键字template 告诉编译器我们下面写的这个函数是一个函数模板
当函数模板被调用时,模板参数T会进行实例化相对应的类型,例如当我们传参进行两个整数的运算时,模板参数T自动实例化成int,同理,当我们传参浮点数进行运算时,T会实例化出double。
类模板
类模板格式
类模板的格式和函数模板相同
关键字template + <class/typname T>
这里class和typname是等价的 这里模板参数可以用任意字母 一般用T
类模板通过类似于函数传参将模板参数进行实例化
通过之前的学习我们接触过的类模板参数用途有好几种,其一就是例如C++标准库中的容器vector,通过类模板参数T,实现容器各种不同数据类型数据的存储,这里能够更好的体会泛型编程的好处,要是C++没有引入泛型编程,vector底层通过函数重载,得写各种类型存储vector容器。其二就是在模拟实现list中的时候,见识到了通过多定义模板参数更简洁高效实现了普通迭代器和const迭代器;其三,在实现反向迭代器时,利用类模板参数,通过正向迭代器复用进行实现
类型模板参数解决typedef后只能存储单个数据的窘境
非类型模板参数
非类型模板参数可以增强模板的灵活性,它允许模板定义中使用常数作为模板参数
类型模板参数和非类型模板参数的区分
类型模板参数顾名思义,用来表示数据的类型的例如通过静态数组类模板中的T,非类型模板参数,而N就属于非类型模板参数
利用非类型模板参数定义静态数组类,通过宏也可以进行实现,但是会出现局限,例如以上代码当我们想要进行将静态数组a1开十个空间,将静态数组a2开二十个空间时,通过宏就没有办法进行解决,但是通过非模板类型参数就可以轻易解决。
非类型模板参数的注意事项
- 能够作为非类型模板参数的只能是整形家族中的 例如 int、size_t、long、char、bool
- 非类型模板参数在编译期就能够确认结果
模板的特化
函数模板的特化
通过特化去解决特别的问题,例如我们想要取通过指针比较指针指向的地址处数据的大小,如果我们不进行处理直接用指针进行比较的话,比较的是指针指向的地址在进行比较,显然这并不是我们想要的结果,所以说不符合模板的情况下我们需要进行特化处理。
函数模板特化的格式:
template<>
函数类型 函数名<函数特化的类型>(形参)注意:函数形参表的类型和个数必须和模板函数相同,否则编译器会报一些奇奇怪怪的错误
解决办法:
方法一:通过函数重载进行解决
方法二:通过函数模板的特化进行解决
思考:当出现模板解决不了的问题,两种解决办法的代码都存在时,会走哪一部分的代码去解决问题呢??当然是函数重载啦,因为函数重载是直接给出来的,而函数模板的特化还是需要实例化出来相对应的类型,然后再进行走函数特化的部分。
在涉及到模板处理不了的问题时,我们一般通过函数重载进行解决,函数重载的代码可读性高。
类模板的特化
同样是去处理通过模板难以处理的问题
全特化
全特化是将模板所有的模板参数都进行确定化
偏特化
偏特化是一种对于模板加了一些限制,分为部分特化和参数进一步限制两种类型
-
部分特化
将一部分的参数进行特化处理
-
参数进一步限制
将参数进行进一步限制,所设计的一个特化版本
模板的分离编译
什么是模板的分离编译
一个程序有多个源文件共同组成,每个源文件又会单独编译成目标文件(例如,
.o
或.obj
文件),然后通过链接器生成可执行文件对于我们程序来说通过使用分离编译能够增强代码的可维护性,我们通常都会使用分离编译和模块化进行程序的开发,但是模板的分离编译并不是这样,使用模板的函数和类都不建议使用模板的分离编译,那么这是为什么呢,我们下面通过分析解决一下这个问题。
假如进行模板分离编译
使用模板的注意事项:
不将模板进行分离编译,防止出现链接不上
若进行分离编译,进行显示实例化(不推荐使用)
模板总结
优点:
通过使用模板,节省资源,增加开发效率
缺点:
代码膨胀,编译速率变慢
出现模板编译错误时,错误信息非常凌乱,不易定位错误