模板参数分为 类型形参 和 非类型形参
#include
using namespace std;
// T 为类型参数,N 为非类型参数,只可以当常量使用
//模板参数的缺省规则和函数参数的缺省规则一样
template<class T, size_t N = 10>
class Array
{
public:
size_t capaciyt() const
{
return N;
}
private:
T arr[N];
};
int main()
{
Array<int> a1;
Array<int, 20> a2;
// 输出 10 20
cout << a1.capaciyt() << " " << a2.capaciyt() << endl;
return 0;
}
用模板可以实现通用的函数和类,但是有时想要对该模板中的某些类型进行特殊化处理,就需要使用模板特化,函数模板和类模板都可以进行特化,但通常函数模板特化可以用函数重载替代
模板特化的语法:
1. 必须要先有一个基础的函数模板或类模板
2. 模板关键字 template 后跟 <>,<> 中写出未特化的类型,都特化了就不写
如果是偏特化中的满足条件特化则需要使用 typename 关键字后跟偏特化的类型
3. 函数名或类名后跟 <>,<> 中指定需要特化的类型,未特化的类型也需要写出
4. 函数名或类名、函数形参表需要和原模板保持一致
模板特化的使用:
#include
using namespace std;
// 定义一个通用的小于的仿函数
template<class T>
struct Less
{
bool operator()(const T& x, const T& y)
{
return x < y;
}
};
// 对 int* 进行特化
template<>
struct Less<int*>
{
bool operator()(const int* x, const int* y)
{
return *x < *y;
}
};
int main()
{
// 创建匿名对象调用 less 模板,输出 1
cout << Less<int>()(1, 2) << endl;
// 如果还是调用 less 模板,便只能用地址比较,可能输出 0
// 通过特化后,可以用指针指向的内容进行比较,输出 1
int* p1 = new int(1);
int* p2 = new int(2);
cout << Less<int*>()(p1, p2) << endl;
return 0;
}
模板特化分为 全特化 和 偏特化(半特化)
#include
using namespace std;
// 类模板
template<class T1, class T2>
class demo
{
public:
// 构造函数
demo()
{
cout << "demo" << endl;
}
};
// 全特化
template<>
class demo<int, char>
{
public:
demo<int, char>()
{
cout << "demo" << endl;
}
};
// 偏特化,对部分参数特化
template<class T1>
class demo<T1, double>
{
public:
demo<T1, double>()
{
cout << "demo" << endl;
}
};
// 偏特化,对满足条件的类型特化
// 当两个参数都是指针类型时的特化
template<typename T1, typename T2>
struct demo<T1*, T2*>
{
public:
demo<T1*, T2*>()
{
cout << "demo" << endl;
}
};
int main()
{
// 调用模板,输出 demo
demo<int, int> d1;
// 调用全特化,输出 demo
demo<int, char> d2;
// 调用偏特化中的部分特化,输出 demo
demo<int, double>d3;
// 调用偏特化中的满足条件特化,输出 demo
demo<int*, double*>d4;
return 0;
}
通常在写项目时,都会将声明写在 .h 文件中,定义写在 .cpp 文件中,但是对于函数模板和类模板而言,如果将声明和定义分离,将会出现链接错误
// demo.h
#pragma once
#include
using namespace std;
template<class T>
class demo
{
public:
// 声明函数
demo();
};
// demo.cpp
#include "demo.h"
// 定义函数
template<class T>
demo<T>::demo()
{
cout << "demo()" << endl;
}
// test.cpp
#include "demo.h"
int main()
{
demo<int> d;
return 0;
}
// demo.cpp
#pragma once
#include
using namespace std;
template<class T>
class demo
{
public:
// 声明函数
demo();
};
// 定义函数
template<class T>
demo<T>::demo()
{
cout << "demo()" << endl;
}
// test.cpp
#pragma once
#include
using namespace std;
template<class T>
class demo
{
public:
// 声明函数
demo();
};
int main()
{
demo<int> d;
return 0;
}
编译完成后,由于 test.cpp 文件中有 demo 的声明,因此 demo
解决方法:
// 在 demo.cpp 文件中,像如下声明需要使用的类型
template
demo<int>::demo();
// 只写 demo.h 文件,不需要 demo.cpp 文件
#pragma once
#include
using namespace std;
template<class T>
class demo
{
public:
// 声明函数
demo();
};
// 定义函数
template<class T>
demo<T>::demo()
{
cout << "demo()" << endl;
}
模板优点:模板增加了代码的复用性
模板缺点:模板出现编译错误时,错误信息非常凌乱,不容易查找到错误