【C++】模板进阶--保姆级解析(什么是非类型模板参数?什么是模板的特化?模板的特化如何应用?)
目录
一、前言
二、什么是C++模板?
💦泛型编程的思想
💦C++模板的分类
三、非类型模板参数
⚡问题引入⚡
⚡非类型模板参数的使用⚡
🔥非类型模板参数的定义
🔥非类型模板参数的两种类型
🔥非类型模板参数的使用规则
⚡问题的解决⚡
⚡非类型模板参数的实例应用⚡
四、模板的特化
💧 概念
💧 函数模板特化
💧 类模板特化
🔥全特化🔥
🔥偏特化🔥
💧模板特化的应用示例
五、总结
六、共勉
一、前言
在我们学习C++时,常会用到函数重载。而函数重载,通常会需要我们编写较为重复的代码,这就显得臃肿,且效率低下。重载的函数仅仅只是类型不同,代码的复用率比较低,只要有新类型出现时,就需要增加对应的函数。此外,代码的可维护性比较低,一个出错可能会导致所有的重载均出错。
那么,模板的出现,就让这些问题有了解决方案,在之前的文章中已经详细的讲解了C++的 ----- 模板初阶,所以本次博客将为大家详细的讲解C++的模板进阶!!
二、什么是C++模板?
程序设计中经常会用到一些程序实体:它们的实现和所完成的功能基本相同,不同的仅 仅是所涉及的数据类型不同。而模板正是一种专门处理不同数据类型的机制。
模板------是泛型程序设计的基础(泛型generic type——通用类型之意)。
函数、类以及类继承为程序的代码复用提供了基本手段,还有一种代码复用途径——类属类型(泛型),利用它可以给一段代码设置一些取值为类型的参数(注意:这些参数 的值是类型,而不是某类型的数据),通过给这些参数提供一些类型来得到针对不同类 型的代码。
💦泛型编程的思想
首先我们来看一下下面这三个函数,如果学习过了C++函数重载 和 C++引用 的话,就可以知道下面这三个函数是可以共存的,而且传值会很方便
void Swap(int& left, int& right)
{
int temp = left;
left = right;
right = temp;
}
void Swap(double& left, double& right)
{
double temp = left;
left = right;
right = temp;
}
void Swap(char& left, char& right)
{
char temp = left;
left = right;
right = temp;
}
但是真的很方便吗?这里只有三种类型的数据需要交换,若是我们需要增加交换的数据呢?再CV然后写一个函数吗?
这肯定是不现实的,所以很明显函数重载虽然可以实现,但是有一下几个不好的地方:
- 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数
- 代码的可维护性比较低,一个出错可能所有的重载均出错
那是否能做到这么一点,告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码
⭐总结:
所以,总结上面的这么一个技术,C++的祖师爷呢就想到了【模版】这个东西,告诉编译器一个模子,然后其余的工作交给它来完成,根据不同的需求生成不同的代码
这就是👉泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础
💦C++模板的分类
1️⃣: 函数模板(function tempalte):使用泛型参数的函数(function with generic parameters)
2️⃣:类模板(class template):使用泛型参数的类(class with generic parameters)更加具体 模板初阶知识 大家这一去看看之前的文章 ----- 模板初阶
本篇文章主要讲解 模板的高阶操作:非类型模板参数、全特化、偏特化等,以及关于模板声明与定义不能分离(在两个不同的文件中)的问题。
三、非类型模板参数
之前所使用的模板参数都是用来匹配不同的类型,如 int、double、Date 等,模板参数除了可以匹配类型外,还可以匹配常量(非类型),完成如数组、位图等结构的大小确定
⚡问题引入⚡
问题:
假设我现在自定义了一个静态栈,栈的大小设置为100。然后我构建了一个int 的类型的栈st1,和一个double 类型的栈st2。那么我希望stl 的大小为100,st2 的大小为500,能不能实现呢?
-------------- 肯定是不能的! ! !
如下面这个例子所示:
#define N 100 // 静态栈 template class Stack { private: int _a[N]; int _top; }; int main() { Stack st1; Stack st1; return 0; }- 从上图 可以发现,栈 的两个对象 的大小都为 100。
那有什么办法 可以解决这个问题呢?
这个时候,就要引出 ---- 非类型模板参数
⚡非类型模板参数的使用⚡
我们知道模板参数分为 : 类型形参 与 非类型形参
- 类型模板形参 : 出现在模板参数列表中,跟在 class 或者 typename 类之后的参数类型名称。
template // T 为模板参数中的 ---------- 类型模板形参
- 非类型模板形参 : 就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。
template // N 为模板参数中的 ------- 非类型模板形参
🔥非类型模板参数的定义
在定义模板参数时,可以不再使用 class 或 typename,而是直接使用具体的类型,如 size_t,此时称为 非类型模板参数
注:非类型模板参数必须为常量,即在编译阶段确定值
🔥非类型模板参数的两种类型
1️⃣: 利用 非类型模板参数 定义一个大小可以自由调整的 整型数组 类
template class arr { public: T& operator[](size_t pos) { assert(pos >= 0 && pos
- 非类型模板形参 : 就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。
- 类型模板形参 : 出现在模板参数列表中,跟在 class 或者 typename 类之后的参数类型名称。
- 从上图 可以发现,栈 的两个对象 的大小都为 100。


