C++20 引入的 Concepts(概念)是一种强大的类型检查工具,它让编程语言在编译时就能对模板参数进行更细粒度的约束。与传统的 SFINAE 方式相比,Concepts 代码更加直观、可维护,并且能够生成更友好的错误信息。下面我们将从概念的基本语法、常用标准概念以及实际使用场景三方面进行阐述。
1. 概念的基本语法
概念本质上是一个布尔表达式,描述了类型需要满足的一系列要求。最常见的定义方式如下:
template<typename T>
concept Integral = std::is_integral_v <T>;
template<typename T>
concept Addable = requires(T a, T b) {
{ a + b } -> std::same_as <T>;
};
Integral:要求T为整数类型。可以直接使用 `std::is_integral_v ` 这一标准类型特性。Addable:使用requires语句来描述表达式a + b的合法性,并且要求结果类型与T相同。
一旦定义好概念,就可以在函数或类模板的参数列表中使用:
template<Integral T>
T max(T a, T b) {
return a > b ? a : b;
}
template<Addable T>
T sum(T a, T b) {
return a + b;
}
如果调用 max 时传入非整数类型,编译器会给出“concept constraint not satisfied”的错误信息,而不是一堆冗长的 SFINAE 消息。
2. 常用标准概念
C++20 标准库已经提供了大量预定义的概念,涵盖了容器、迭代器、算术、可比较等类别。常用的概念包括:
| 概念 | 描述 | 示例 |
|---|---|---|
std::integral |
整数类型 | int, long |
std::floating_point |
浮点类型 | float, double |
std::same_as<T1, T2> |
两个类型完全相同 | std::same_as<int, int> |
| `std::equality_comparable | ||
| 支持==|std::string` |
||
| `std::weakly_incrementable | ||
| 迭代器可以前移 |std::vector::iterator` |
||
| `std::input_iterator | ||
| 可读迭代器 |std::istream_iterator` |
使用这些标准概念可以避免手动编写复杂的类型特性:
#include <concepts>
template<std::integral T>
T factorial(T n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
3. 实际使用场景
3.1 约束算法实现
#include <vector>
#include <ranges>
template<std::weakly_incrementable Iter>
auto sum_range(Iter first, Iter last) {
using T = std::iter_value_t <Iter>;
T sum{};
for (; first != last; ++first) {
sum += *first;
}
return sum;
}
在此例中,sum_range 只要求迭代器满足 weakly_incrementable,不关心具体容器类型。调用时可直接传入 `std::vector