本文整理自《C++必知必會》條款 47-54,系統講解模板特化機制、依賴名稱消歧、成員模板、類型萃取等進階主題,是模板元編程的基石。
template void f(T); // 主模板
template void f(T*); // 重載,非特化
template class Heap; // 主模板
template class Heap { ... }; // 局部特化:所有指釖類型
template<> class Heap { ... }; // 完全特化:const char*
優先級規則:完全特化 > 局部特化 > 主模板。實參為 const char* 時匹配完全特化;其他指釖匹配局部特化。
template class Heap { ... }; // 針對固定大小數組
特化整個類 vs 特化單個成員函數:
// 主模板
template class Heap {
public: void push(const T& val);
};
// 成員函數完全特化
template<> void Heap::push(const char* const & pval) { ... }
關鍵規則:若存在局部特化 Heap,則 Heap 必須匹配局部特化中的簽名(參數為 T* 而非 const T&)。
在模板中,編譯器無法判斷 T::iterator 是類型還是靜態成員,需加 typename:
template
void print(const T& c) {
typename T::const_iterator it = c.begin(); // 告訴編譯器這是類型
...
}
成員本身是模板,常用於構造函數接受迭代器範圍:
template
class Slist {
public:
template
Slist(In begin, In end); // 成員模板
};
template
template
Slist::Slist(In begin, In end) : head_(0) {
while (begin != end) push_front(*begin++);
reverse();
}
當依賴名稱是模板時,需在 :: 後加 template:
template>
class SList {
typedef typename A::template rebind::other NodeAlloc; // 正確
// typedef A::rebind::other NodeAlloc; // 錯誤:編譯器以為 rebind 是靜態成員
};
typename 告訴編譯器「整個表達式是類型」,template 告訴編譯器「rebind 是模板」。
template struct IsInt { enum { result = false }; };
template<> struct IsInt { enum { result = true }; };
template
void aFunc(X& arg) {
if (IsInt::result) { /* X 是 int */ }
}
這是 Traits 技法 的雛形:透過特化提取類型屬性。
容器通過嵌套 typedef 暴露類型信息:
template
class Seq {
public:
typedef T Elem; // 元素類型
typedef T Temp; // 臨時對象類型
size_t size() const;
};
typedef Seq Strings;
Strings::Elem aString; // 編譯期獲取元素類型
將類型相關操作封裝到獨立 Traits 類,實現「非侵入式」類型擴展:
template struct CharTraits; // 主模板
template<> struct CharTraits { // 完全特化
static void assign(char&, char);
static bool eq(char, char);
// ...
};
標準庫 std::char_traits、std::iterator_traits、std::numeric_limits 皆屬此類。
| 技術 | 關鍵字 | 用途 |
|---|---|---|
| 類模板完全特化 | template<> | 特定類型完全不同實現 |
| 類模板局部特化 | template<T> Class<T*> | 一類類型共享實現 |
| 成員函數特化 | template<> void Class<T>::f() | 單一函數特化 |
| 依賴類型聲明 | typename | 嵌套類型名稱 |
| 依賴模板名稱 | template | 嵌套模板名稱 |
| Traits | 特化結構體 | 類型屬性萃取 |
using 別名模板(C++11)替代嵌套 typedefstd::void_t (C++17) 實現 SFINAE 檢測std::conditional, std::enable_if 等標準 Traits 工具