C++ 模板进阶知识点详解
1. 非类型模板参数
C++ 中的模板不仅可以接受类型参数(如>
T),还可以接受非类型参数。非类型模板参数允许您将常量值(如整数或指针)传递给模板。这些参数在编译时被计算,因此非常适用于创建更灵活和高效的代码。
但是,使用非类型模板参数时有以下限制:
- 不能使用浮点数、类对象或字符串作为非类型模板参数。
- 非类型模板参数必须在编译时就能确定其值。
示例:
cpp
template<int N>
class Array {
public:
int arr[N];
};
在这个例子中,N 就是一个非类型模板参数,代表数组的大小。
2.模板的按需实例化
按需实例化意味着模板实例化仅在模板的特定实例被实际使用时才会发生。这种方式能够有效减少编译的冗余,提高编译效率。在某些情况下,模板可能在源文件中声明但并未直接使用,只有在某个地方显式使用时,编译器才会进行实例化。

3. 模板特化
模板特化允许为某些类型或条件定义特定的模板实现。当通用模板实现不适用于某些类型时,或者需要模板的特殊版本时,可以使用模板特化。
3.1 函数模板特化
函数模板特化允许针对特定类型给出不同的实现。例如,当处理指针时,默认的模板比较可能是比较指针地址,而不是指针指向的对象内容。
函数模板的特化步骤:
- 必须要先有一个基础的函数模板
- 关键字template后面接一对空的尖括号<>
- 函数名后跟一对尖括号,尖括号中指定需要特化的类型
- 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误
示例:
cpp
template <typename T>
bool Less(T left, T right) {
return left < right;
}
// 指针类型的特化
template <>
bool Less<Date*>(Date* left, Date* right) {
return *left < *right;
}
在这个例子中,特化确保了在比较指针时,实际上是比较指针指向的对象,而不是指针的地址。
3.2 类模板特化
类模板特化允许根据类型不同提供不同的实现。可以对类模板进行完全特化,为特定类型提供专门的实现。
示例:
cpp
template <class T>
class Data {
public:
Data() { cout << "Generic Data" << endl; }
private:
T _d;
};
// 对 `int` 类型的特化
template <>
class Data<int> {
public:
Data() { cout << "Specialized Data<int>" << endl; }
private:
int _d;
};
3.3 部分特化
部分特化允许对模板参数列表中的部分参数进行特化。这种方法更加灵活,可以在不完全特化整个模板的情况下,处理特定的模式。
示例:
cpp
template <typename T1, typename T2>
class Data { /* 通用模板实现 */ };
// 当第二个参数为 `int` 时的特化
template <typename T1>
class Data<T1, int> { /* 对 `int` 类型的特化实现 */ };
4. 模板分离编译
4.1什么是分离编译
一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式。
4.2模板分离编译
cpp
// a.h
template<class T>
T Add(const T& left, const T& right);
// a.cpp
template<class T>
T Add(const T& left, const T& right)
{
return left + right;
}
// main.cpp
#include"a.h"
int main()
{
Add(1, 2);
Add(1.0, 2.0);
return 0;
}

4.3 解决方法:
模板代码通常定义在头文件中,但将声明和定义分开可能会导致问题。模板需要在实例化时能够访问到其定义,因此在分离编译时需要格外小心。通常有两种分离模板代码的方法:
- 将模板定义和声明放在同一个头文件(推荐使用这种方法)。
- 显式实例化模板(不推荐使用)。
5. 总结
模板的优点:
- 代码复用:模板可以让代码针对不同类型进行通用化,节省资源并减少冗余。
- 灵活性:模板增强了代码的灵活性,支持泛型编程。
- STL:C++ 标准模板库(STL)就是通过模板实现的,展示了模板在实际应用中的强大功能。
模板的缺点:
- 代码膨胀:过度使用模板可能导致代码膨胀。
- 编译时间变长:模板实例化会增加编译时间。
- 错误信息难以理解:与模板相关的错误通常会产生难以理解的编译器错误信息。