從一個「通用加法函數」出發,理解為什麼 C++ 需要模板、什麼是泛型編程。本文涵蓋函數模板、類模板、實例化機制、實參推演、特化、重載規則等核心知識點,配合編譯器輸出圖解,打牢泛型編程根基。
早期嘗試:
泛型編程 = 編寫與類型無關的代碼,以不變的代碼框架承載可變的類型。模板是其 C++ 實現基石。
template <typename T> // 或 class T
返回類型 函數名(參數列表) { ... }
template <typename T>
T Add(T left, T right) { return left + right; }
int main() {
Add(1, 2); // OK,推演 T=int
Add(1, 2.0); // Error:兩個實參類型不同,無法確定單一 T
}

operator+)。fun(1, 'a', 3.14) → fun<int, char, double>
編譯器不會隱式轉換實參以匹配已有實例化,而是產生新實例:
template<typename T> T Add(T a, T b); int Add(int a, int b); // 非模板版本 Add(1.2, 3.4); // 生成 Add<double>,而非轉 int 調用非模板版

僅允許兩種轉換:
const 轉換(非 const → const 引用/指針)typename T / class Ttemplate<typename T, int Size> void sum(T (&arr)[Size])命名規則:同一參數列表中不可重名;遵循作用域遮蔽規則。



int Max(int a, int b); // 非模板 template<typename T> T Max(T a, T b); // 模板1 template<typename T> T Max(T a, T b, T c); // 模板2 Max(10, 20); // 調用非模板(優先) Max<>(10, 20); // 強制調用模板1 Max(10, 20.12); // 調用模板1(double 更好匹配) Max<int>(10.0, 20.0); // 顯式指定 T=int
核心原則:非模板優先;模板不隱式轉換;Max<> 強制只考慮模板。
為特定類型提供定制實現:
template<typename T> int cmp(const T& a, const T& b) { return a - b; }
template<> int cmp<const char*>(const char*& a, const char*& b) {
return strcmp(a, b); // 字符串比較特化
}
要求:實參類型必須與特化版形參完全匹配(含 const/引用)。
template<typename T> class SeqList {
int _size, _capacity; T* _data;
public:
SeqList() : _size(0), _capacity(10), _data(new T[_capacity]) {}
~SeqList() { delete[] _data; }
};
SeqList<int> sl1; // 必須顯式指定 T=int
SeqList<double> sl2; // 編譯器生成 SeqList<double> 完整類定義
不同於函數模板,類模板使用時必須顯式提供模板實參。
| 特性 | 函數模板 | 類模板 |
|---|---|---|
| 實參推演 | 自動(調用時) | 不支持(必須顯式) |
| 特化 | 函數模板特化 | 類模板特化/偏特化 |
| 預設參數 | 不支持 | 支持(template<typename T=int>) |
| 編譯模型 | 包含模型(頭文件含定義) | 包含模型 |
模板是 C++ 泛型編程的基石,掌握其推演、實例化、特化規則,是寫出高效、安全、可復用庫代碼的前提。