概念(Concepts)是 C++20 为模板编程带来的重要新特性,它们通过在编译时对类型参数做约束,使代码更具可读性、可维护性,并能在编译阶段捕获错误。本文将从概念的基本定义、语法到实际使用场景展开介绍,并结合完整代码示例帮助读者快速上手。
1. 概念的基本语法
template<typename T>
concept Integral = std::is_integral_v <T>;
template<typename T>:模板参数声明。concept Integral:概念名称。- `std::is_integral_v `:约束表达式,返回布尔值。若为 `true`,类型满足该概念。
使用概念时,可以在模板参数后直接写约束:
template<Integral T>
T add(T a, T b) {
return a + b;
}
如果传入非整数类型,编译器会给出明确的错误信息。
2. 组合与命名约束
概念之间可以用逻辑运算符组合,形成更复杂的约束。
template<typename T>
concept Arithmetic = Integral <T> || std::is_floating_point_v<T>;
template<Arithmetic T>
T multiply(T a, T b) {
return a * b;
}
约束别名
C++20 允许给约束起别名,提升可读性:
template<typename T>
concept Arithmetic = Integral <T> || std::is_floating_point_v<T>;
template<Arithmetic T>
T power(T base, unsigned int exp);
3. 约束表达式中的逻辑
&&:逻辑与||:逻辑或!:逻辑非->:返回类型约束(用于requires语句)
template<typename T>
concept ValidContainer = requires(T a) {
a.begin();
a.end();
{ *a.begin() } -> std::same_as<typename T::value_type&>;
};
上述约束检查一个容器是否满足 begin()、end() 并且 *begin() 的返回类型与 value_type& 相同。
4. 需要注意的编译器支持
- GCC 10+、Clang 10+、MSVC 19.29+ 已基本支持概念。
- 若使用旧编译器,需开启
-std=c++20或等效选项。
5. 实战案例:通用排序函数
#include <iostream>
#include <vector>
#include <algorithm>
#include <concepts>
#include <type_traits>
// 1. 定义概念
template<typename T>
concept Arithmetic = std::is_arithmetic_v <T>;
template<typename Container>
concept RandomAccessContainer = requires(Container c) {
typename Container::value_type;
{ c.begin() } -> std::same_as<typename Container::iterator>;
{ c.end() } -> std::same_as<typename Container::iterator>;
{ *c.begin() } -> std::same_as<typename Container::value_type&>;
};
// 2. 约束版排序
template<RandomAccessContainer C>
void generic_sort(C& container) {
std::sort(container.begin(), container.end());
}
// 3. 使用示例
int main() {
std::vector <int> v = { 5, 2, 9, 1, 5, 6 };
generic_sort(v);
std::cout << "Sorted vector: ";
for (int n : v) std::cout << n << ' ';
std::cout << '\n';
return 0;
}
说明
RandomAccessContainer约束确保容器具备随机访问迭代器,满足std::sort的要求。- 若传入
std::list,编译器会报错,提示不满足约束。 - 使用概念后,错误信息更直观,例如“容器必须是随机访问容器”。
6. 进阶:概念与模板偏特化
概念可以与模板偏特化配合使用,实现更细粒度的行为控制。
template<typename T, typename Enable = void>
struct Printer { /* default */ };
template<typename T>
struct Printer<T, std::enable_if_t<Integral<T>>> {
static void print(T value) { std::cout << "Integral: " << value << '\n'; }
};
template<typename T>
struct Printer<T, std::enable_if_t<std::is_floating_point_v<T>>> {
static void print(T value) { std::cout << "Floating: " << value << '\n'; }
};
使用概念简化上述实现:
template<Integral T>
struct Printer <T> {
static void print(T value) { std::cout << "Integral: " << value << '\n'; }
};
template<std::floating_point T>
struct Printer <T> {
static void print(T value) { std::cout << "Floating: " << value << '\n'; }
};
7. 小结
- 概念:在编译时对模板参数进行约束,提升错误诊断。
- 语法:
concept关键字,requires子句,逻辑运算符。 - 优势:更易读、易维护、编译期错误更明确。
- 实践:可用于容器、数值类型、迭代器等多种场景。
掌握概念后,你的模板代码将更加健壮,也更贴近自然语言的表达,极大提升 C++20 开发体验。祝编码愉快!