Concepts 用关键字+布尔表达式定义约束,核心是声明类型能力并由编译器静态检查;std::is_*用于简单元信息判断,requires表达式检查实际操作能力,标准库概念应优先复用。

直接用 concept 关键字 + 布尔表达式就能定义约束,不需要宏、traits嵌套或SFINAE绕弯子。核心就两点:写清楚“这个类型得能干啥”,编译器会帮你静态检查。
用 std::is_* 特征做简单类型分类
适合判断内置属性,比如是不是整数、有没有默认构造函数。这类约束写法最直白,但只看类型元信息,不检查实际可用的操作。
-
std::is_integral_v<t></t>是编译期常量,直接当布尔值用,别漏掉_v后缀 - 必须包含
<type_traits>,否则std::is_integral_v不可见 - 这种定义方式不能捕获“类型是 int,但 operator+ 被删了”这类语义错误
template<typename T>
concept Integral = std::is_integral_v<T>;
<p>template<Integral T>
T square(T x) { return x * x; }
用 requires 表达式检查操作能力
这才是 Concepts 的主力用法:不是问“你是什么类型”,而是问“你能做什么”。编译器会尝试解析花括号里的表达式,只要语法合法且满足返回类型要求,就算通过。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
-
{ a + b }只检查表达式可写,不关心返回值类型;加-> std::same_as<T>才强制返回同类型 - 参数名(如
T a, T b)只是占位符,不参与求值,但影响可读性 - 多个需求写在同一
requires块里是“与”关系;分开写多个requires是“或”关系(极少用)
template<typename T>
concept Addable = requires(T a, T b) {
{ a + b } -> std::same_as<T>;
};
<p>template<Addable T>
T add(T a, T b) { return a + b; }
组合标准库概念构建复合约束
C++20 标准库在 <concepts> 里预置了一批常用概念,比如 std::integral、std::copyable、std::equality_comparable。它们已经过充分测试,优先复用,别自己重复造轮子。
立即学习“C++免费学习笔记(深入)”;
- 组合时用逻辑运算符:
template<std::integral T> requires std::copyable<T> - 注意
std::integral和std::is_integral_v<T>不等价:前者还要求可比较、可转换等额外语义 - 标准概念可能隐含比你预期更强的约束,比如
std::regular包含可复制、可比较、可哈希等一整套要求
容易忽略的细节:约束不满足时的报错位置
Concepts 错误不会出现在模板展开深处,但具体报在哪一行,取决于你把约束写在哪——这是最容易被低估的实操点。
- 如果写成
template<MyConcept T>,错误指向模板声明行 - 如果写成
template<typename T> requires MyConcept<T>,错误指向requires行 - 如果函数体里有
static_assert(MyConcept<T>),那就退化回传统方式,错误指向 assert 行,失去 Concepts 的优势 - 别在概念定义里调用未声明的函数或访问私有成员,否则报错会变成“找不到符号”,而不是“不满足概念”

















