接續基礎篇,本文深入探討類模板實例化機制、成員函數特性、非類型參數實現容器適配器、STL 六大組件中的配接器與仿函數、模板特化(全特化/偏特化)及分離編譯方案。
核心原則:編譯器遇到模板定義不生成代碼,只有實例化時才生成具體代碼。這影響代碼組織方式與錯誤檢測時機。
普通函數/類:聲明在 .h,定義在 .cpp,鏈接器解析符號。
模板不同:實例化需要看到完整定義 → 模板頭文件通常包含聲明與定義。
template <class ...> // 或 typename
class ClassName { ... };
template <typename T>
class SeqList {
public:
SeqList() : _size(0), _capacity(10), _data(new T[_capacity]) {}
~SeqList() { delete[] _data; }
private:
int _size, _capacity;
T* _data;
};
void test() {
SeqList<int> sl1;
SeqList<double> sl2; // 編譯器生成兩個獨立類
}
<Type>template <typename T>
class SeqList {
SeqList& operator++() { return *this; } // 類內可直接用 SeqList,無需 SeqList<T>
};
SeqList<T>& SeqList<T>::operator++() { ... } // 類外需完整限定
template <class T, int N>
class SeqList { T a[N]; }; // 固定大小數組,N 為編譯時常量
模板參數可以是模板本身,這是 STL 容器適配器的基礎:
template <typename T>
class SeqList { ... }; // 底層容器
// 容器適配器:接受模板模板參數,提供缺省值
template <typename T, template <class> class Container = SeqList>
class Stack {
public:
void Push(const T& x);
void Pop();
const T& Top();
bool Empty();
private:
Container<T> _con; // 使用傳入的容器模板實例化
};
void Test() {
Stack<int> s1; // 使用默認 SeqList
Stack<int, SeqList> s2; // 顯式指定
}
stack、queue、priority_queue(底層默認 deque)reverse_iterator、insert_iterator、ostream_iterator 等bind1st、bind2nd、not1、not2 等(C++11 後用 std::bind/lambda 替代)
仿函數(Functor)是重載 operator() 的類對象,行為像函數,但可攜帶狀態、支持模板化。
class Greater {
public:
bool operator()(int a, int b) { return a > b; }
};
class Less {
public:
bool operator()(int a, int b) { return a < b; }
};
template <class Com = Greater>
void BubbleSort(int* a, int size) {
Com com;
for (int i = 0; i < size; ++i) {
bool sorted = true;
for (int j = 0; j < size - i - 1; ++j) {
if (com(a[j], a[j+1])) { // 使用仿函數比較
std::swap(a[j], a[j+1]);
sorted = false;
}
}
if (sorted) break;
}
}
// 使用
BubbleSort<Less>(arr, n); // 遞增
BubbleSort<Greater>(arr, n); // 遞減
template <typename T>
class SeqList { ... };
// 全特化 int 版本
template <>
class SeqList<int> {
public:
SeqList(int capacity); // 可改變構造簽名
~SeqList();
private:
int _size, _capacity;
int* _data;
};
// 類外定義成員不加 template<>
SeqList<int>::SeqList(int capacity) : _size(0), _capacity(capacity), _data(new int[_capacity]) {
std::cout << "SeqList<int>\n";
}
針對模板參數進一步條件限制:
// 原始模板
template <typename T1, typename T2>
class Data { ... };
// 偏特化 1:固定 T2 為 int
template <typename T1>
class Data<T1, int> { ... };
// 偏特化 2:兩個參數均為指針
template <typename T1, typename T2>
class Data<T1*, T2*> { ... };
// 偏特化 3:兩個參數均為引用
template <typename T1, typename T2>
class Data<T1&, T2&> { ... };
使用示例:
Data<int, double> d1; // 原始模板 Data<int, int> d2; // 偏特化 1 Data<int*, double*> d3; // 偏特化 2 Data<int&, double&> d4; // 偏特化 3

推薦方案:將聲明與定義放入同一
.hpp文件。
不推薦:頭文件顯式實例化template class SeqList<int>;(編譯器支持度低、實例化依賴調用者)
| 優點 | 缺點 |
|---|---|
| 代碼復用、類型安全、性能零開銷、支撐 STL | 編譯緩慢、錯誤信息晦澀、代碼膨脹、調試困難 |