模板是 C++ 泛型編程的基石,實現「編寫一次,適用多類型」的零開銷抽象。本文系統講解函數模板、類模板、非類型參數、模板特化、參數推導規則、別名模板、可變參數模板 (C++11) 及 Concepts (C++20) 等核心知識,並給出工程級編碼規範。
template // 或 class T
T Max(T a, T b) {
return (a > b) ? a : b;
}
// 顯式實例化 (指定模板參數)
int n = Max(3, 5); // 生成 int Max(int, int)
// 隱式實例化 (參數推導)
double d = Max(3.14, 2.71); // 推導 T=double,生成 double Max(double, double)
編譯器為每組具體模板參數生成獨立函數代碼(代碼膨脹風險),類似宏但帶類型檢查、作用域、重載解析。
template
T1 Max(T1 a, T2 b) { return (a > b) ? a : b; }
Max(10, 20); // T1=int, T2=int
Max(10, 3.14); // T1=int, T2=double (隱式轉換)
Max(10, 3.14); // T1=double, T2=double (顯式指定 T1,T2 用默認)
Max(int, int) 同時有普通版與模板版會報錯。decltype(auto) (C++14)template
auto Add(T a, U b) -> decltype(a + b) { return a + b; } // C++11
template
decltype(auto) Add(T a, U b) { return a + b; } // C++14 保留引用/const 屬性
template
class Array {
T data_[N];
public:
T& operator[](size_t i) { return data_[i]; }
size_t size() const { return N; }
};
Array arr; // 實例化為具體類型 Array
arr[0] = 42;
template
T& Array::operator[](size_t i) { return data_[i]; } // 必須帶模板參數列表
std::pair p(1, 3.14); // 推導 std::pair
std::vector v = {1,2,3}; // 推導 std::vector
Array arr = {1,2,3,4,5}; // 推導 Array (需 C++20 或提供推導向導)
編譯期常量:整型、枚舉、指針/引用 (外部鏈接)、std::nullptr_t、浮點型 (C++20)、字面值類型 (C++20)。
template
struct Buffer { T data[N]; };
template // C++17 自動推導類型
struct S { static constexpr auto value = N; };
template class Container, typename T>
void print(const Container& c) { ... }
print(std::vector{1,2}); // OK
print(std::list{1,2}); // OK
template
struct Hash { size_t operator()(T v) const { return std::hash{}(v); } };
template <> // 全特化:參數列表為空
struct Hash {
size_t operator()(const std::string& s) const {
return std::hash{}(s); // 避免拷貝
}
};
template
struct PtrTraits { static constexpr bool is_ptr = false; };
template
struct PtrTraits { // 偏特化:指針類型
static constexpr bool is_ptr = true;
using pointee_type = T;
};
改用 重載 實現同等效果:
template void func(T); // 基礎模板
template void func(T*); // 重載:指針版本
void func(int*); // 普通函數:int* 專用
template
using Vec = std::vector>;
Vec v; // 等價 std::vector>
// 遞歸終止
void print() { std::cout << '\n'; }
// 遞歸展開
template
void print(T first, Args... rest) {
std::cout << first << ' ';
print(rest...);
}
print(1, 2.5, "hello", 'c'); // 1 2.5 hello c
折疊表達式 (C++17) 簡化求和/拼接:
template
auto sum(Args... args) { return (args + ...); } // 左折疊 (args1 + (args2 + ...))
template
concept Addable = requires(T a, T b) { a + b; };
template
T Add(T a, T b) { return a + b; } // 編譯期報錯信息極其清晰
export 關鍵字,極少編譯器支援)。void* 內部實現 + 模板包裝)。typename 而非 class:語義更清晰,嵌套從屬類型必須加 typename (C++20 部分場景可省略)。template void func(T&& param) 配合 std::forward(param) 保持值類別。enable_if / Concepts:約束模板適用範圍,避免難懂的編譯錯誤。extern template class MyClass; (頭文件) + template class MyClass; (單一 cpp) 減少編譯時間與目標碼體積。模板不是「高級宏」,而是編譯期圖靈完整的類型計算系統。從 std::vector 到 std::variant,從 STL 算法到 Boost.Hana,現代 C++ 庫的表達力皆建立於模板之上。熟練掌握 參數推導、特化、可變參數、Concepts,是編寫高性能、可維護、可擴展泛型代碼的核心技能。