C++ 模板
C++ 的 模板(Template)提供了一种在编译期对类型和常量进行参数化的机制,是实现泛型编程(Generic Programming)的核心。模板能够让同一份代码适用于多种类型,消除重复,同时还能借助特化和约束,实现高度灵活的库设计。下面分章介绍其主要形式与高级特性。
1. 函数模板
定义一族同名函数,编译器在调用时根据实参类型自动生成对应版本:
// 通用 swap
template<typename T>
void swap_(T& a, T& b) {
T tmp = std::move(a);
a = std::move(b);
b = std::move(tmp);
}
// 使用
int x = 1, y = 2; swap_(x, y);
std::string s1 = "A", s2 = "B"; swap_(s1, s2);
- 模板参数列表:
template<typename T>
(或template<class T>
) - 参数推导:调用时可省略显式模板实参
swap_<int>(x,y)
,编译器自动推导T=int
。
2. 类模板
将类型参数化的类定义,可实例化成不同类型版本:
template<typename T>
class Box {
T value_;
public:
explicit Box(const T& v): value_(v) {}
T get() const { return value_; }
void set(const T& v) { value_ = v; }
};
// 使用
Box<int> bi(42);
Box<double> bd(3.14);
- 类模板可以有多个模板参数:
template<typename T, size_t N>
- 支持默认模板参数:
template<typename T = int> class Vec { … };
3. 非类型模板参数
模板参数不仅限于类型,也可是整型、指针等常量:
template<typename T, std::size_t N>
struct FixedArray {
T data[N];
constexpr std::size_t size() const { return N; }
};
FixedArray<int, 10> arr;
非类型参数在编译期已知,可用于尺寸、策略选择等。
4. 模板特化
4.1 完全特化
为某个特定类型提供专门实现:
template<typename T>
struct Printer {
static void print(const T& x) { std::cout << x; }
};
// 对 char* 专门化
template<>
struct Printer<char*> {
static void print(char* s) { std::cout << '"' << s << '"'; }
};
4.2 偏特化(仅对类模板)
对一类模板参数组合重载:
// 通用版本
template<typename T, typename U>
struct Pair { /*…*/ };
// 当两个类型相同时的偏特化
template<typename T>
struct Pair<T, T> { /*…*/ };
函数模板不支持偏特化,可用重载或 enable_if
替代。
5. 变参模板(C++11 起)
允许任意数量的模板参数和函数参数:
// 函数变参模板
template<typename... Args>
void log_all(Args&&... args) {
(std::cout << ... << args) << "\n"; // fold expression
}
// 使用
log_all(1, " + ", 2.5, " = ", 3.5);
typename... Args
:参数包- 展开:
(expr(args),…)
或 C++17 的折叠表达式
6. SFINAE 与 std::enable_if
“Substitution Failure Is Not An Error” 允许在模板参数推导失败时剔除某些重载,实现条件化重载:
#include <type_traits>
template<typename T>
auto foo(T x)
-> std::enable_if_t<std::is_integral_v<T>, void> {
std::cout << "integral\n";
}
template<typename T>
auto foo(T x)
-> std::enable_if_t<std::is_floating_point_v<T>, void> {
std::cout << "floating\n";
}
C++20 中可用 概念(Concept) 更直观地约束模板。
7. C++20 概念与约束
概念(concept
)提供了第一类语法支持的模板约束,替代繁琐的 enable_if
:
template<typename T>
concept Addable = requires(T a, T b) {
{ a + b } -> std::same_as<T>;
};
template<Addable T>
T add(T a, T b) {
return a + b;
}
requires
表达式 用于检查操作合法性- 调用
add(std::string, std::string)
合法,但add(int, std::string)
编译时报错。
小结
- 函数模板、类模板 是实现类型无关代码的手段;
- 非类型参数、模板特化、变参模板 大幅提升灵活性;
- SFINAE 和 概念 为模板添加编译期约束,保证更早发现错误;
- 合理运用这些特性,可以构建高性能、可重用且类型安全的泛型库。