C++模板

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

typenameclass 在模板参数里完全等价: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. 两种实例化方式

  1. 隐式实例化(自动推演):上面调用 max(1,2),编译器自动推导出 T=int,自动生成代码。
  2. 显式实例化:手动指定类型,强制生成代码
    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++允许同时存在:同名普通函数 + 函数模板,构成重载,编译器有固定匹配优先级:

  1. 优先匹配完全匹配的普通非模板函数(优先级最高);
  2. 无匹配普通函数,再用函数模板推演实例化;
  3. 模板推演有多个候选,选最匹配的。

代码示例

// 普通非模板函数
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版本

整体知识脉络总结

  1. 模板分两大分支:函数模板、类模板;
  2. 模板只是蓝图,使用时触发实例化生成实体(模板函数/模板类);
  3. 模板参数两类:类型参数(代表类型)、非类型参数(编译期常量);
  4. 函数独有:模板实参自动推演;
  5. 特化:给特定类型定制专属逻辑,分全特化、偏特化;
  6. 重载规则:普通函数 > 模板函数,可共存重载。

需要我把以上知识点整理一份可直接编译的完整综合示例代码吗?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值