template
class AutoList { ... }; // AutoList 是模板,非類型
AutoList myList; // 錯誤:缺少模板參數
AutoList intList; // 正確:實例化為具體類型 AutoList
AutoList longList; // 另一個獨立類型
編譯器根據模板參數實例化生成具體代碼。每組參數生成一份代碼——代碼膨脹風險需注意。
template inline T test(const T&); // 正確
inline template T test(const T&); // 錯誤:inline 必須在 template 之後
T (&)[N])可保留大小資訊,避免退化為指標導致類型不匹配。const 轉換規則:非 const 實參可傳給 const 引用/指標參數(安全);傳值參數忽略 const。export)已被 C++ 標準移除。template
class Test { ... };
Test<80, 60> obj; // 實參必須為編譯期常數表達式
template class Container = vector>
class MyStack { ... };
// .h
template class Test { void setData(const T&); T getData(); };
// .cpp
template void Test::setData(const T& v) { ... }
template T Test::getData() { ... }
template class Test; // 顯式實例化 int 版本
template
struct Factorial { enum { value = N * Factorial::value }; };
template <> struct Factorial<0> { enum { value = 1 }; };
Factorial<5>::value; // 編譯期得到 120
將運算從執行期遷移至編譯期,提前發現錯誤,提升執行效能(代價:編譯時間變長)。
// 顯式介面 + 執行期多態
void doProcessing(Widget& w) { if (w.size() > 10) { Widget tmp(w); tmp.normalize(); tmp.swap(w); } }
// 隱式介面 + 編譯期多態
template
void doProcessing(T& w) { if (w.size() > 10) { T tmp(w); tmp.normalize(); tmp.swap(w); } }
w != nasty 不要求 T 有 operator!=,只要存在可轉換的比較運算子即可。class 與 typename 等價。template
void print2nd(const C& container) {
typename C::const_iterator* x; // 必須加 typename
// ...
}
例外:基類列表、成員初始化列表中的基類修飾符不可加 typename。
模板函式多載解析時,若模板實參替換導致無效型別/運算式,編譯器不報錯,直接從多載集移除該候選,嘗試其他多載。核心技術:
typedef char TrueType;
struct FalseType { char a[2]; };
template static TrueType TestIsClass(int C::*); // 類型有成員指標
template static FalseType TestIsClass(...); // 通配
template
struct IsClass {
enum { OK = (sizeof(TestIsClass(0)) == sizeof(TrueType)) };
};
編譯期判斷 T 是否為類類型。SFINAE 讓「非類型」匹配通配版本,避免硬錯誤。
模板揭示了 C++ 泛型編程的博大精深。從實例化機制、推演規則、元編程到 SFINAE,每一層都值得深入探索。泛型編程與面向對象並重,構成現代 C++ 的雙輪驅動。