C++ Templates 模板全套知识点详解
一、基础概念:模板、函数模板 / 类模板
1. 什么是模板
模板是C++泛型编程核心,把类型/常量做成参数,一份代码适配多种数据类型,避免重复写 int/float/string 版本的重复代码。
本质:编译器根据传入参数,自动生成对应类型的函数/类代码(代码生成机制)。
2. 函数模板(通用函数)
语法:template<参数列表> + 普通函数
// T 是类型参数,代表任意类型
template<typename T>
T max(T a, T b) {
return a > b ? a : b;
}
// 调用
max(1, 2); // T=int
max(3.14, 2.5); // T=double
typename 和 class 在模板参数里完全等价:template<class T> 效果一样。
3. 类模板(通用容器/数据结构)
语法:template<参数列表> + 类定义
template<typename T>
class Vector {
private:
T* data;
public:
void push_back(T val);
T get(int idx);
};
// 使用
Vector<int> vi; // 存储int的数组
Vector<string> vs; // 存储字符串的数组
二、模板的实例化、模板函数 / 模板类
1. 模板本身≠可执行代码
template<...> 只是蓝图/图纸,不会生成机器码;只有用到具体类型时,编译器才会生成实体代码,这个过程叫实例化。
2. 模板函数
函数模板实例化后,生成的具体类型函数称为模板函数:
template<typename T> void func(T) {}
func(10); // 实例化 void func<int>(int) → 模板函数
func(3.14); // 实例化 void func<double>(double) → 另一个模板函数
3. 模板类
类模板实例化后得到的具体类叫模板类:
template<typename T> class Box {};
Box<int> b1; // 实例化得到 Box<int> 模板类
Box<string> b2; // Box<string> 另一个独立类
4. 两种实例化方式
- 隐式实例化(自动推演):上面调用
max(1,2),编译器自动推导出T=int,自动生成代码。 - 显式实例化:手动指定类型,强制生成代码
template int max<int>(int, int); // 显式实例化int版本max template class Vector<double>; // 显式实例化Vector<double>
三、模板实参的推演(函数模板专属)
只针对函数模板,编译器自动从函数入参推导模板参数T,不用手动写 <int>。
1. 基础推演
template<typename T> void print(T x) {}
print(99); // 实参int → T=int
print("abc"); // 实参const char[4] → T=const char*
2. 推演限制场景(无法自动推演,必须显式指定)
模板参数只出现在返回值,不出现在函数形参时,推演失效:
template<typename T> T create() { return T(); }
create<int>(); // 必须手动写<int>,没有入参无法推T
3. 推演匹配规则
- 数组实参 → 推演为指针;
- const/引用会参与推演;
- 自动忽略顶层const(底层const保留)。
四、模板的类型参数 / 非类型参数
模板尖括号 <> 里分两种参数:类型参数、非类型参数。
1. 类型参数(最常用)
用 typename/class 修饰,代表一种数据类型(int、string、自定义类等)
template<typename T, class U> // T、U都是类型参数
void swap(T& a, U& b) {}
2. 非类型参数(常量参数)
不是类型,是编译期常量值,支持整数、指针、引用、枚举等,必须是编译期确定的值。
语法:直接写类型+参数名,不加 typename
// N是非类型参数,编译期常量整数
template<int N>
class Array {
private:
int buf[N]; // 固定大小数组,大小由N指定
};
Array<10> arr1; // N=10
Array<256> arr2; // N=256
限制:
- 不能传变量:
int n=5; Array<n> x;报错,n是运行期变量; - C++17前非类型参数不能是浮点数、类对象。
五、模板的特化 / 特例化(Specialization)
通用模板对所有类型一套逻辑;特化为某一类/某一个类型单独重写一套逻辑,分全特化、偏特化。
1. 全特化(完全特化)
给模板所有参数指定固定值,针对单一类型单独实现。
示例:通用Vector,单独给 bool 类型特殊优化
// 通用类模板
template<typename T>
class Vector { /* 通用实现 */ };
// bool类型全特化版本
template<> // 尖括号空,所有参数都指定死了
class Vector<bool> {
// 单独优化:用bit存储bool,节省内存
};
函数模板全特化:
template<typename T> void show(T x) { cout << x; }
template<> void show<string>(string s) { cout << "字符串:" << s; }
2. 偏特化(部分特化,仅类模板支持)
只固定一部分模板参数,剩余参数依然泛型。
示例:模板有T、N两个参数,只固定N=64,T任意
template<typename T, int N> class Buffer {};
// 偏特化:N固定64,T仍可变
template<typename T>
class Buffer<T, 64> {
// N=64专属逻辑
};
特化优先级
调用时优先匹配特化版本,没有特化才走通用基础模板。
六、模板函数和非模板函数的重载
C++允许同时存在:同名普通函数 + 函数模板,构成重载,编译器有固定匹配优先级:
- 优先匹配完全匹配的普通非模板函数(优先级最高);
- 无匹配普通函数,再用函数模板推演实例化;
- 模板推演有多个候选,选最匹配的。
代码示例
// 普通非模板函数
void max(int a, int b) {
cout << "普通int版本";
return a > b ? a : b;
}
// 函数模板
template<typename T>
T max(T a, T b) {
cout << "模板泛型版本";
return a > b ? a : b;
}
max(1, 2); // 匹配普通int函数,不走模板
max(3.1, 2.9); // 无匹配普通函数,调用模板double版本
max("a", "b"); // 调用模板const char*版本
手动强制走模板
就算有普通函数,想强制使用模板版本,加空尖括号:
max<>(1, 2); // 强制触发模板推演,调用模板int版本
整体知识脉络总结
- 模板分两大分支:函数模板、类模板;
- 模板只是蓝图,使用时触发实例化生成实体(模板函数/模板类);
- 模板参数两类:类型参数(代表类型)、非类型参数(编译期常量);
- 函数独有:模板实参自动推演;
- 特化:给特定类型定制专属逻辑,分全特化、偏特化;
- 重载规则:普通函数 > 模板函数,可共存重载。
需要我把以上知识点整理一份可直接编译的完整综合示例代码吗?

963

被折叠的 条评论
为什么被折叠?



