模板的特化
分全特化,偏特化(也叫半特化)
非类型模板参数也是可以特化的
使用场景:
在优先级队列中,正常情况,如果我们想要比较整形家族(例如
int
,char
)的数据时,可以用模板来传参,就可以比较大小了。
template<class T>
struct Less
{
bool operator()(const T& x,const T& y) const
{
return x < y;
}
};
但是我想要在类里面比较较为复杂的类型时,比如日期类Date。传参就传了指针,那么,并不能达到我们比较日期的目的,所以我们需要对这个类型进行特殊化处理(特化)。
template<>
strcut Less<Data*>
{
bool operator()(Data* x, Data* y) const
{
return *x < *y;
}
};
这里是类模板特化,还有函数模板特化
模板的分离编译
首先什么是分离编译?
一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件连接起来形成单一的可执行文件的过程。
假如有以下场景,模板的声明与定义分离开,在头文件中进行声明,源文件中完成定义:
// a.h
template<class T>
T Add(const T& x, const T& y);
// a.cpp
template<class T>
T Add(const T& x, const T& y)
{
return x + y;
}
// test.cpp
#include"a.h"
int main()
{
Add(1, 2);
Add(1.0, 2.0);
return 0;
}
但这样写可行吗?
我们知道程序运行的步骤:
其实模板
在test.cpp中,编译它调用Add()
函数时,编译器只知道有一个Add()
函数的声明,编译器没有看到对Add
模板函数的实例化,因此不会生成具体的加法函数。
在main.obj中调用的Add<int>
与Add<double>
,编译器在链接时才会找其地址,但是这两个函数没有实例化没有生成具体代码,因此链接时报错。
解决方法
- 将声明和定义放到一个文件 “xxx.hpp” 里面或者xxx.h,也是可以的。——推荐使用这种
- 模板定义的位置显式实例化。—— 这种方法不实用,不推荐使用
那类模板呢?
我们使用某个类都要调用它的构造函数,所以其实类模板和函数模板在这里是一样的。
仿函数
对于排序算法来说,我们需要对不同的对象进行比较就可能需要不同的比较函数,这样才能排序。然而C语言提供的解决方法就是回调函数和函数指针,说实在的比较晦涩难懂罢。到了C++我们就选择使用仿函数来解决。
看如下仿函数Less
template<class T>
struct Less
{
bool operator()(const T& x,const T& y) const
{
return x < y;
}
};
其实就是重载了( )
这个运算符的一个类。
模板的优劣
复用了代码,减少重复工作,更加方便开发,STL也是因此而诞生的。
增强了代码灵活性。
导致了代码膨胀,虽然不用模板也要写这么多代码,但是容易误以为很少。也会导致代码运行时间增加(主要是模板实例化导致的)。
出现模板编译错误时,报错会变得很多,不容易定位错误(雀食)。