文章目录
模板的特殊化
模板的特化是对已经存在的模板
进行的特殊处理
通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些我们不想要的结果需要特殊处理
例如
写一个比较函数,如果是直接写成下图的函数模板,我们就只能按照规定好的大小比较方式进行比较
上图的比较虽然按照语法来说是正确的
但是如果我们想写一个当传入的参数的类型是int*
的时候,比较的方式是指针解引用之后再比较的话,如果只有上图中的模板就做不到了
这个时候就可以对特殊化出一个模板,专门处理我们的特殊要求
可以看到,这样就完成了我们的对int*类型特殊处理的要求
函数模板特化的作用
作用很简单:
传入的具体类型如果拥有对应的特化模板函数,就会优先调用
那个特化的模板函数
例如上面举例的比较大小的模板函数Greater
,如果传给Greater
的参数类型是int*,那就会优先调用int*特化的模板函数
因为函数模板特化的作用基本只有这个,所以其实函数模板的特化是有替代的,那就是普通的函数没错就是普通的函数,模板初阶【模板初阶【C++】】中就说过,如果既有函数模板又有普通函数时,在传递参数都不会类型转换的情况下,编译器就会优先调用普通函数
例
所以其实函数模板的特化其实挺鸡肋的,因为直接写成普通函数还更好
- 因为它的语法限制比普通函数多
- 在函数模板特化和普通函数共存时,甚至还会优先调用普通函数
但是类模板的特化就有用得多了
函数模板的的特殊化
语法:
template<>
返回值 函数名<具体类型,具体类型,……>(参数表)
{
函数体
}
例
具体类型就是要特殊处理的类型【特化类型】
函数模板特化的要求
- 因为模板的特化是对
已经存在的模板
进行的特殊处理
所以必须要先有一个基础的函数模板(母板
),才能对这个模板进行特殊化 - 关键字template后面的尖括号<>里面一定得是空的,这是
语法规定
,不是空的就报错
- 特化的模板函数的参数表:
必须
要和基础的函数模板(母板)的参数完全相同
人话:写出来的特化的模板函数的参数表,与把特化类型传给基础的函数模板(母板)后实例化出来的模板函数的参数表一样
不然可能会出现很多奇怪的错误,此时要是实在解决不了,就直接实现成全局函数就行了
类模板的特殊化
类模板的特殊化的要求
因为:模板的特化是对已经存在的模板
进行的特殊处理
和函数模板一样,必须要先有一个基础的类模板(母板
),才能对这个类模板进行特殊化
类模板的特殊化的语法
template<空 或者 模板参数,模板参数,……>
class 类名<具体类型/加上限制的模板参数>
{
类体
}
全特化
全特化就是把基本类模板(母板)的模板参数全部实例化
例
全特化了之后,当传给类模板的参数和全特化的模板实例化的参数完全相同
的时候,就会调用全特化的类模板实例化对象
如下图:
偏特化
偏特化分两种:
实例化部分模板参数
这样偏特化了之后,传给类模板的参数和偏特化
的类模板部分实例化
的参数完全相同
的时候,就会调用偏特化的类模板进行实例化对象
例
如下图,当传给A类的模板参数,第一个是int时将会调研偏特化的类模板实例化对象
第一个模板参数不是int的时候,才会调用基本类模板(母板)进行实例化对象
对基本类模板(母板)的模板参数进行限制
不实例化基本类模板(母板)的模板参数,而是对它加上限制【加const
,*{指针限制}
,&(引用限制)
等】
这样偏特化了之后,传给类模板的参数和偏特化
的限制的
参数完全相同
的时候,就会调用偏特化的类模板进行实例化对象
例
如下图,偏特化加上的限制是*{指针限制}
,所以如果传给类模板的模板参数都是指针类型
的就会调用偏特化的类模板进行对象的实例化
实例化c对象的时候传给类模板的模板参数都是指针类型,所以调用了偏特化的类模板
实例化b对象的时候传给类模板的模板参数只有第一个是指针类型
,并没有与偏特化
的限制的
参数完全相同
,所以调用的还是基本类模板(母板)
非类型模板参数
非类型参数:
就是用一个常量
作为类模板或者函数模板的一个参数,在模板中可将该参数当成常量来使用
例如:
自己封装一个静态数组,此时就可以用非类型模板参数作为静态数组的容量
大小
非类型模板参数的特点(注意点)
-
C++20
以前
非类型模板参数的类型只能是整型或者char类型
-
C++20
以后
非类型模板参数的类型支持所有内置类型
,但不能
是自定义类型 -
非类型模板参数
可以给
缺省值 -
因为非类型模板参数是常量,所以它接收的参数也必须是
常量
或者是const修饰的变量
例
传变量就会报错