C++ 模板基础
函数模板
// 不用模板 → 写 N 个重载
int max(int a, int b) { return a > b ? a : b; }
double max(double a, double b) { return a > b ? a : b; }
// 用模板 → 一个搞定所有类型
template <typename T>
T max(T a, T b) {
return a > b ? a : b;
}
auto r1 = max(3, 5); // T = int
auto r2 = max(3.14, 2.71); // T = double
auto r3 = max<float>(3, 5.0); // 显式指定 T = float
// 多个模板参数
template <typename T, typename U>
auto add(T a, U b) -> decltype(a + b) { // C++11 后置返回类型
return a + b;
}
// C++14 简化:auto 自动推导返回类型
template <typename T, typename U>
auto add(T a, U b) {
return a + b;
}
类模板
template <typename T>
class Stack {
vector<T> data;
public:
void push(const T &val) { data.push_back(val); }
T pop() {
T val = data.back();
data.pop_back();
return val;
}
bool empty() const { return data.empty(); }
};
Stack<int> intStack;
Stack<string> strStack;
非类型模板参数
// 编译期固定大小的数组
template <typename T, size_t N>
class Array {
T data[N];
public:
T &operator[](size_t i) { return data[i]; }
size_t size() const { return N; }
};
Array<int, 10> arr; // 10 个 int,栈上分配
Array<double, 5> arr2; // 5 个 double
模板特化
// 通用模板
template <typename T>
class Traits {
public:
static const char *name() { return "unknown"; }
};
// 全特化
template <>
class Traits<int> {
public:
static const char *name() { return "int"; }
};
template <>
class Traits<double> {
public:
static const char *name() { return "double"; }
};
cout << Traits<int>::name(); // "int"
cout << Traits<float>::name(); // "unknown" (走通用模板)
SFINAE 入门
Substitution Failure Is Not An Error — 替换失败不是错误。
// 仅在 T 有 .size() 方法时启用
template <typename T>
auto getSize(const T &t) -> decltype(t.size()) {
return t.size();
}
// C++20 Concept 替代方案(更可读)
// template <typename T>
// requires requires(T t) { t.size(); }
// auto getSize(const T &t) { return t.size(); }
常见陷阱
// ❌ 模板定义放在 .cpp → 链接错误
// ✅ 模板定义必须放在头文件(或显式实例化)
// ❌ 忘记 typename
template <typename T>
void foo() {
typename T::value_type x; // 告诉编译器 T::value_type 是类型
}
// ❌ 模板递归太深 → 编译超时
// ✅ 考虑用折叠表达式(C++17)替代递归