template <class T, int Size = 100> // 類型參數 + 非類型參數(有默認值)
class Buffer {
T data[Size];
// ...
};
// 使用
Buffer<int> buf1; // 使用默認 Size=100
Buffer<double, 256> buf2; // 顯式指定非類型參數
class T 或 typename T (等價)std::nullptr_t,必須是編譯期常量template<class> class Container隱式實例化:使用模板類型時 (定義對象、sizeof、派生等) 自動觸發。
Buffer<int> buf; // 觸發 Buffer<int> 實例化
sizeof(Buffer<double>); // 觸發實例化以獲取大小
class Derived : Buffer<char> {}; // 觸發實例化
顯式實例化:template class Buffer<int>; 強制編譯器生成代碼,常用於庫的顯式導出。
// 類內定義 (隱式 inline)
template <class T> class Stack {
void push(const T& val) { elems.push_back(val); } // 內聯
T pop() { T val = elems.back(); elems.pop_back(); return val; }
private:
vector<T> elems;
};
// 類外定義 (需帶模板參數)
template <class T>
void Stack<T>::push(const T& val) { elems.push_back(val); }
關鍵點:成員函數本身也是模板,僅在被調用時才實例化,未調用的成員不生成代碼 (支持 SFINAE)。
| 類型 | 語法 | 關係 |
|---|---|---|
| 非模板友元 | friend class Other; friend void func(); | 所有實例共享同一友元 |
| 綁定友元模板 | template<class T> friend class Friend<T>; | 一對一:Buffer<int> 友元 Friend<int> |
| 非綁定友元模板 | template<class U> friend class Friend; | 一對多:所有 Buffer 實例友元所有 Friend 實例 |
// 綁定友元需前置聲明
template <class T> class Friend;
template <class T> class Buffer {
friend class Friend<T>; // 綁定
};
template <class T> class Friend { /* 可訪問 Buffer<T> 私有成員 */ };
template <class T> class Counter {
static int count; // 每個實例化類型擁有獨立靜態成員
public:
static int get() { return count++; }
struct Nested { T value; }; // 嵌套類型也是模板
};
template <class T> int Counter<T>::count = 0; // 類外定義靜態成員
// 使用
Counter<int>::get(); // 0
Counter<int>::get(); // 1
Counter<double>::get(); // 0 (獨立計數)
Counter<int>::Nested n; // 嵌套類型需前綴實例化類名
class Widget {
public:
// 構造函數模板:接受任何可轉換為 T 的類型
template <class T> Widget(const T& val) : value(val) {}
// 成員函數模板
template <class T> void process(const T& param) { /* ... */ }
// 嵌套類模板
template <class T> struct Handler { void operator()(T&) {} };
private:
int value;
};
// 使用
Widget w(3.14); // T=double
w.process("hello"); // T=const char*
Widget::Handler<int> h;
成員模板極大增強了類的泛化能力,標準庫智能指針構造函數即大量使用此技術。
| 模型 | 特點 | 優點 | 缺點 |
|---|---|---|---|
| 包含模型 | 聲明+定義全在頭文件 | 編譯器可見完整定義,支持內聯優化,最通用 | 編譯依賴重,頭文件大,編譯慢 |
| 分離模型 | 聲明在頭文件,定義在 .cpp,用 export | 隱藏實現,減少編譯依賴 | 極少編譯器支持 (僅 EDG 前端),C++11 棄用 |
| 顯式實例化聲明 | 頭文件聲明 extern template class Foo<int>;,.cpp 顯式實例化 | 控制實例化位置,減少重複編碼,加快編譯 | 需預知使用的類型,擴展性受限 |
現代最佳實踐:包含模型 (頭文件唯一) + 顯式實例化聲明 優化編譯速度。C++20 Modules 將徹底解決此問題。
// 通用模板
template <class T>> class Serializer { /* 通用序列化 */ };
// 全特化:針對 string 優化
template <> class Serializer<string> {
public:
static string to_json(const string& s) { return "\"" + escape(s) + "\""; }
};
// 成員函數全特化
template <> void Serializer<int>::serialize(int val) { /* 整數特化邏輯 */ }
// 通用:兩個類型參數
template <class T1, class T2> class Pair { /* ... */ };
// 偏特化 1:第二個參數固定為 int
template <class T> class Pair<T, int> { /* 針對 int 優化 */ };
// 偏特化 2:指針類型
template <class T> class Pair<T*, T*> { /* 指針對專用邏輯 */ };
// 偏特化 3:引用類型
template <class T> class Pair<T&, T&> { /* 引用對專用 */ };
匹配規則:編譯器選擇最特化的版本。偏特化本身是模板,需提供完整成員定義。
namespace MyLib {
template <class T> class Vector { /* ... */ };
template &<class T> T max(const T& a, const T& b) { return a
#include <vector> <stdexcept> <string>
using namespace std;
template <class T> class Stack {
vector<T> elems;
public:
void push(const T& elem) { elems.push_back(elem); }
void push(T&& elem) { elems.push_back(std::move(elem)); }
void pop() {
if (elems.empty()) throw out_of_range("Stack empty");
elems.pop_back();
}
T top() const {
if (elems.empty()) throw out_of_range("Stack empty");
return elems.back();
}
bool empty() const { return elems.empty(); }
size_t size() const { return elems.size(); }
};
// 使用
int main() {
Stack<int> intStack;
intStack.push(7);
cout << intStack.top() << endl; // 7
Stack<string> stringStack;
stringStack.push("hello");
cout << stringStack.top() << endl; // hello
}
// 基本語法
template <class T> T max(T a, T b) { return a < b ? b : a; }
// 類型推導
max(3, 5); // T=int
max(3.14, 2.71); // T=double
max("a", "b"); // T=const char* (比較指針地址!需特化或重載)
// 顯式指定模板參數
max<double>(3, 4.5); // T=double, 隱式轉換
// 多參數模板
template <class T, class U> auto add(T a, U b) -> decltype(a+b) { return a+b; }
模板參數 ├─ 類型參數 (class/typename) ├─ 非類型參數 (整型/指針/引用/模板模板) └─ 默認參數 (右向左) 實例化機制 ├─ 隱式 (使用時) ├─ 顯式 (template class Foo;) └─ 成員函數按需 (調用時) 特化層級 ├─ 全特化 (template<> class Foo {}) ├─ 偏特化 (類模板: template class Foo {}) └─ 函數模板無偏特化 (用重載替代) 編譯模型 ├─ 包含模型 (主流) ├─ 顯式實例化聲明 (優化編譯) └─ Modules (C++20 未來) 進階特性 ├─ 成員模板 (構造/函數/嵌套類) ├─ 別名模板 (template using Vec = vector ;) ├─ 變長模板 (template ) └─ 概念/約束 (C++20 concepts)
模板是 C++ 泛型編程的基石,掌握其實例化機制、特化規則、編譯模型與進階特性,是編寫高效、通用、可維護 C++ 庫代碼的關鍵。