c++ requires子句怎么写 c++ Concepts约束详解【详解】

21次阅读

c++20 的 requires 子句是 Concepts 的核心语法,用于编译期静态约束模板参数;常见位置在模板参数后、函数声明前,支持布尔常量表达式、concept 名复用及 requires 表达式检查表达式合法性。

c++ requires子句怎么写 c++ Concepts约束详解【详解】

C++ 的 requires 子句用于在模板定义中直接表达对模板参数的约束,它是 C++20 Concepts 的核心语法之一。它不是“写在函数末尾的条件判断”,而是编译期静态检查的声明式约束工具,让错误信息更清晰、接口意图更明确。

requires 子句的基本写法

最常见写法是跟在模板参数列表后、函数声明前,用 requires 关键字引导一个布尔常量表达式:

template requires std::is_integral_v T add(T a, T b) { return a + b; }

也可以把约束写成内联形式(更紧凑):

template   requires std::is_integral_v  // 注意:这里不能加分号 T add(T a, T b) { return a + b; }

注意:requires 后必须是编译期可求值的常量表达式(constexpr bool),不能含运行时变量或非 constexpr 函数调用。

立即学习C++免费学习笔记(深入)”;

用 concept 名字简化 requires 子句

比起重复写长表达式,推荐先定义 concept,再在 requires 中复用:

template concept Integral = std::is_integral_v;  template requires Integral T add(T a, T b) { return a + b; }

这样语义清晰,也支持逻辑组合:

  • requires Integral && (sizeof(T) > 2)
  • requires Integral || FloatingPoint(需提前定义 FloatingPoint
  • requires !std::is_const_v(带否定)

requires 子句的位置变体

requires 不只出现在函数模板前,还有三种合法位置:

  • 函数模板头之后(最常用):template<...> requires ... void f();
  • 作为函数声明的一部分(尾随 requires)void f() requires C;(适用于类成员函数或已有模板参数推导上下文)
  • 在 template 参数列表中直接约束模板形参template void f(T);(这是 concept 作为类型约束的简写,等价于 template requires Integral

三者语义一致,选哪种取决于可读性和上下文习惯。尾随写法在类内定义成员函数时更自然。

requires 表达式:检查表达式是否合法

除了布尔常量,requires 还支持 requires 表达式(一种特殊的 Lambda 式语法),用于检查某表达式能否通过编译:

template concept Addable = requires(T a, T b) {   { a + b } -> std::same_as;  // 要求 a+b 存在且返回 T 类型   { a += b };                        // 只要求能编译,不关心返回值 };

这种写法本质是编译器尝试实例化花括号内的代码块;只要所有子句都满足,整个 requires 表达式为 true。它比 std::is_invocable 等 trait 更灵活,是构建自定义 concept 的主力。

Concepts 和 requires 不是为了炫技,而是让模板错误从“一长串无法理解的内部展开”变成“Error: concept 'Integral' not satisfied by 'std::String'”。写清楚约束,既是帮编译器,也是帮下一个读你代码的人。

text=ZqhQzanResources