虽然这东西好像没什么记录的必要……但老师对此的描述太好了,不记下来的话难受
类型模板参数:
//C语言(数据结构)期间我们模拟实现时,为了在修改存储数据类型时能更加的便捷,我们使用了typedef:
typedef int DataType;
//而这么写不能让我们在一个代码中存储不同类型的数据,而 C++中,类 型 模 板 解决了这一问题:
template<class T>
class A{……};
A<int> a1; A<double> a2;
非类型模板参数:
//对于以下代码:
#define N 20;
template<class T>
class Array{
private:
T _a[N];
}
//目前为止,我们做不到让不同对象中的 N 不同
//非类型模板参数则能解决这个问题:
template<class T, size_t N> //● 规定这是 整 形 常 量(所以 int N 也是没有问题的)
class Array{
private:
T _a[N];
}
//…………………………
Array<int,10> a1;
Array<double,20> a2;
对某些类型进行特殊化处理
函数模板的特化
//实现一个日期类 Date(略)
template<class>
bool Less(T left, T right){
return left < right;
}
cout << Less(1,2) << endl;//可以比较,结果正确
Date d1(2022,7,7);
Date d1(2022,7,8);
cout << Less(d1,d2) << endl;//可以比较,结果正确
Date* p1 = &d1;
Date* p2 = &d2;
cout << Less(p1,p2) << endl;//可以比较,结果错误
//为了解决这种特殊情况,我们可以使用模板特化(此处为函数模板特化):
template<>
bool Less<Date*>(Date* left, Date* right){
return *left < *right;
}
实际上函数模板的特化意义不大,上面用重载一样能解决问题
类模板的特化:
比如此前在 “栈和队列” 中实现的优先级队列,我们用仿函数去控制大小堆,当存储对象为日期类的指针时,我们需要再写一个仿函数 PDateGreater 并在创建对象时主动传入。
但如果我们总要储存这样的对象,每次都主动传入 PDateGreater 未免有些麻烦,于是就可以用类模板解决这一问题:
//类中原本的仿函数
template<class T>
struct less
{
bool operator()(const T& x, const T& y)
{
return x < y;
}
};
//类模版
template<>
struct less<Date*>
{
bool operator()(const Date* x, const Date* y)
{
return *x < *y;
}
};
偏特化 示例1:
//●上面类模版的特化用的是是全特化,也可以用偏特化:
template<>
struct less<T*>
{
bool operator()(const T* x, const T* y)
{
return *x < *y;
}
};
偏特化 示例2:
class Data
{
public:
Data() { cout << "Data" << endl; }
private:
T1 _d1;
T2 _d2;
};
template <class T1>
class Data<T1, int>
{
public:
Data() { cout << "Data" << endl; }
private:
T1 _d1;
int _d2;
};
int main() {
Data<int, double> d1;
Data<int, int> d2;
return 0;
}
模板的特化都是建立在有源模板的基础之上的
准确的说是不能声明和定义不能处于不同的项目文件中
比如这样两个函数:
//Calculate.h
template<class T>
T Add(const T& x, const T& y);
int func(int x, int y);
//Calculate.c
#include"Calculate.h"
template<class T>
T Add(const T& x, const T& y) {
return x + y;
}
int func(int x, int y) {
return x + y;
}
//test.c
#include"Calculate.h"
#include
using namespace std;
int main() {
cout << func(1, 2) << endl;
cout << Add(1, 2) << endl;
}
语法上不会报错(能正常编译),但最后链接时出现问题
原因:预处理过后(经头文件包含,剩下 Calculate.i 和 test.i),正常编译、汇编(我想不用解释),在编译期间,test.i 中只有声明,因而形成如下所示的指令:
func(?) //?表示相应的函数的地址(只根据声明知道你可能在其他文件中定义了这个函数,但不知道具体在哪里)
Add(?)
链接时,func 函数可以实例化,能填充相应的地址,但 Add 不行(不知道T到底是什么,也就没办法实例化)
解决方式:
template<class T>
T Add(const T& x, const T& y);
int func(int x, int y);
template<class T>
T Add(const T& x, const T& y) {
return x + y;
}
int func(int x, int y) {
return x + y;
}
int main() {
cout << func(1, 2) << endl;
cout << Add(1, 2) << endl;
}
函数的定义就在本文件中,编译期间直接实例化并将地址填入,链接?不需要链接:
func(0x~~)
Add(0x~~)
//在 Calculate.c后面加上诸如:
template
double Add<double>(const double& x, const double& y);
template
int Add<int>(const int& x, const int& y);
显然是一种很拉的方法
● 优点:
● 缺陷: