模板与泛型
翻译整理自 cppreference - 模板。
1. 函数模板
template <typename T>
T add(T a, T b) {
return a + b;
}
add<int>(1, 2); // 3
add(1.0, 2.0); // 推断 double
add(std::string("a"), std::string("b"));2. 多类型参数
template <typename T, typename U>
auto sum(T a, U b) -> decltype(a + b) { // C++11 后置返回
return a + b;
}
// C++14 起可省略 trailing return
template <typename T, typename U>
auto sum(T a, U b) { return a + b; }3. 非类型参数
template <typename T, size_t N>
struct Array {
T data[N];
constexpr size_t size() const { return N; }
};
Array<int, 10> a;4. 类模板
template <typename T>
class Stack {
public:
void push(const T& v) { data_.push_back(v); }
T pop() {
T v = data_.back();
data_.pop_back();
return v;
}
private:
std::vector<T> data_;
};
Stack<int> s;
s.push(1);5. 模板特化
全特化
template <typename T>
struct TypeName { static const char* get() { return "unknown"; } };
template <>
struct TypeName<int> { static const char* get() { return "int"; } };
template <>
struct TypeName<double> { static const char* get() { return "double"; } };
TypeName<int>::get(); // "int"
TypeName<float>::get(); // "unknown"
偏特化
template <typename T>
struct Vector { /* general */ };
template <typename T>
struct Vector<T*> { /* pointer specialization */ };6. 变长模板
template <typename... Args>
void log(Args... args) {
(std::cout << ... << args) << '\n'; // C++17 fold
}
log(1, " ", 2.0, " ", "x");7. 概念 Concepts(C++20)
约束模板参数:
#include <concepts>
template <typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;
template <Numeric T>
T add(T a, T b) { return a + b; }
// 简写
auto add2(Numeric auto a, Numeric auto b) { return a + b; }要求检查:
template <typename T>
requires std::integral<T>
T gcd(T a, T b) { ... }8. SFINAE 与 enable_if
C++11 旧式约束:
template <typename T,
typename = std::enable_if_t<std::is_integral_v<T>>>
T half(T x) { return x / 2; }C++20 起用 concepts 替代,更易读。
9. 模板元编程
编译期计算:
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++11+ 推荐 constexpr 替代递归模板:
constexpr int fact(int n) {
return n <= 1 ? 1 : n * fact(n - 1);
}10. 模板编译模型
- 模板定义通常放在头文件中
- 显式实例化
template class Stack<int>;可用于隐藏实现 - C++20 modules 可替代 #include,缓解编译速度问题
小结
C++ 模板是强大的元编程工具,C++20 的 concepts 让错误信息更友好。