在C++20之前,模板的类型约束只能通过 SFINAE(Substitution Failure Is Not An Error)或者概念库(Concepts)等手段来实现,代码往往显得冗长且可读性差。C++20 引入了概念(Concepts)这一特性,让模板的类型检查与普通函数一样直接、易读。本文将通过一系列实例,演示如何使用 Concepts 优化模板代码、提升类型安全,并简化调试流程。
1. 什么是 Concept?
Concept 是一种类型约束,定义了一组类型必须满足的逻辑表达式。Concept 不是类型,而是一个“属性”,可以在函数模板、类模板或变量模板的声明中直接使用。
template<typename T>
concept Integral = std::is_integral_v <T>;
这个概念 Integral 表示 T 必须是整数类型。
2. 基础用法
2.1 函数模板约束
template<Integral T>
T add(T a, T b) {
return a + b;
}
现在如果调用 add(1, 2) 成功;但 add(1.2, 3.4) 会产生编译错误,提示 T 不满足 Integral。
2.2 多约束组合
template<Integral T, typename U>
requires std::is_same_v<T, U>
T mul(T a, U b) {
return a * b;
}
这里使用 requires 关键字来组合两个约束:T 必须是整数,且 T 与 U 必须相同。
3. 复杂概念的构建
3.1 范围概念(Range)
template<typename T>
concept Range = requires(T r) {
{ std::begin(r) } -> std::input_iterator;
{ std::end(r) } -> std::input_iterator;
};
该概念确保 T 可以使用 std::begin 和 std::end,并且返回的是输入迭代器。
3.2 计算型概念(Arithmetic)
template<typename T>
concept Arithmetic = requires(T a, T b) {
{ a + b } -> std::same_as <T>;
{ a - b } -> std::same_as <T>;
{ a * b } -> std::same_as <T>;
{ a / b } -> std::same_as <T>;
};
此概念定义了四则运算操作,且结果类型与输入相同。
4. 在类模板中使用 Concept
template<Arithmetic T>
class Calculator {
public:
T sum(const T& a, const T& b) { return a + b; }
T diff(const T& a, const T& b) { return a - b; }
};
这使得 Calculator 的实例只能为实现算术操作的类型,例如 int、double、`std::complex