模板是 C++ 泛型程式設計基石,支援函數模板、類模板、變量模板、別名模板。本文系統講解模板參數、實參推導、特化、SFINAE、Concepts 約束、變長模板、折疊表達式完整體系。
// 基本語法
template <typename T> // 或 class T
T max(T a, T b) { return a < b ? b : a; }
// 多類型參數
template <typename T, typename U>
auto add(T a, U b) -> decltype(a + b) { return a + b; } // C++14 返回類型推導
// 非類型參數 (編譯期常量)
template <typename T, size_t N>
void print_array(const T (&arr)[N]) { for (auto v : arr) std::cout << v << ' '; }
// 模板參數包 (C++11)
template <typename... Args>
void print_all(Args&&... args) { (std::cout << ... << args) << std::endl; } // C++17 折疊表達式
// 實參推導規則
max(3, 5); // T=int
max(3.14, 2.71); // T=double
max("abc", "def"); // T=const char*
// max(3, 3.14); // 錯誤:推導衝突,需顯式 max<double>(3, 3.14) 或 static_cast
template <typename T>
class Stack {
std::vector<T> elems;
public:
void push(const T& v) { elems.push_back(v); }
void pop() { if (elems.empty()) throw std::out_of_range("empty"); elems.pop_back(); }
T top() const { if (elems.empty()) throw std::out_of_range("empty"); return elems.back(); }
bool empty() const { return elems.empty(); }
};
// C++17 類模板實參推導 (CTAD)
Stack s1 = {1,2,3}; // 推導為 Stack<int>
Stack s2{std::vector{1.0, 2.0}}; // Stack<double>
// 顯式指定 (C++17 前必須)
Stack<std::string> s3;
// 全特化
template <>
class Stack<bool> { // 壓縮 bool 為 bitset
std::vector<unsigned long> bits;
public:
void push(bool v) { /* 位操作 */ }
// ...
};
// 偏特化 (僅類模板支援)
template <typename T>
class Stack<T*> { // 指針特化:存儲指針、所有權語義
std::vector<T*> ptrs;
public:
void push(T* p) { ptrs.push_back(p); }
// ...
};
// 函數模板不支援偏特化,改用重載
template <typename T> void func(T); // 通用
template <typename T> void func(T*); // 指針重載
template <typename T> void func(std::vector<T>); // vector 重載
#include <type_traits>
// C++11: enable_if 做返回類型條件
template <typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
serialize(T value) { /* 整數序列化 */ return value; }
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
serialize(T value) { /* 浮點序列化 */ return value; }
// C++14: enable_if_t 別名簡化
template <typename T>
std::enable_if_t<std::is_enum<T>::value, std::string>
to_string(T e) { return std::to_string(static_cast<std::underlying_type_t<T>>(e)); }
// C++17: if constexpr 編譯期分支 (替代 SFINAE 許多場景)
template <typename T>
void process(T value) {
if constexpr (std::is_integral_v<T>) std::cout << "int: " << value;
else if constexpr (std::is_floating_point_v<T>) std::cout << "float: " << value;
else std::cout << "other";
}
#include <concepts>
// 定義概念
template <typename T>
concept Integral = std::is_integral_v<T>;
template <typename T>
concept SignedIntegral = Integral<T> && std::is_signed_v<T>;
template <typename T>
concept Hashable = requires(T a) {
{ std::hash<T>{}(a) } -> std::convertible_to<size_t>;
};
// 使用概念約束模板參數
template <Integral T>
T abs_val(T x) { return x < 0 ? -x : x; }
template <typename T> requires SignedIntegral<T>
T negate(T x) { return -x; }
// 縮寫函數模板語法 (C++20)
auto add(Integral auto a, Integral auto b) { return a + b; }
// 概念組合
template <typename T> concept Number = Integral<T> || std::is_floating_point_v<T>;
void print(Number auto n) { std::cout << n; }
// 遞歸終止
void print() {}
template <typename T, typename... Rest>
void print(T first, Rest... rest) { std::cout << first << ' '; print(rest...); }
// C++17 折疊表達式
template <typename... Args>
auto sum(Args... args) { return (args + ...); } // 一元右折疊
template <typename... Args>
void print_fold(Args... args) { (std::cout << ... << args) << '\n'; }
// 完美轉發
template <typename F, typename... Args>
decltype(auto) invoke(F&& f, Args&&... args) {
return std::forward<F>(f)(std::forward<Args>(args)...);
}
template <int N> struct Factorial { static constexpr int value = N * Factorial<N-1>::value; };
template <> struct Factorial<0> { static constexpr int value = 1; };
// Factorial<5>::value == 120 (編譯期常量)
// C++17 constexpr 函數替代
constexpr int factorial(int n) { return n <= 1 ? 1 : n * factorial(n-1); }
static_assert 配合 Concepts/Type Traits 給出友善錯誤訊息。template <typename> struct dependent_false : std::false_type {}; 在函數體觸發 static_assert(dependent_false<T>::value, "msg") 延遲斷言。-ftemplate-backtrace-limit=0 (GCC/Clang) 顯示完整實例化堆疊。