requires
expression
(since C++20)
生成一个类型为 bool 的纯右值表达式,用于描述约束条件。
目录 |
语法
requires
{
requirement-seq
}
|
(1) | ||||||||
requires
(
parameter-list
(optional)
)
{
requirement-seq
}
|
(2) | ||||||||
| parameter-list | - | 形参列表 |
| requirement-seq | - | 由多个 要求 组成的序列,每个要求是以下类型之一: |
说明
要求可以引用在作用域内的模板参数、 parameter-list 的参数,以及从外围上下文中可见的任何其他声明。
在 模板化实体 声明中使用的 requires 表达式进行模板参数替换时,可能导致其需求中形成无效的类型或表达式,或违反这些需求的语义约束。在此情况下, requires 表达式会求值为 false 且不会使程序非良构。替换和语义约束检查按词法顺序进行,并在遇到决定 requires 表达式结果的条件时停止。若替换(若存在)和语义约束检查成功,则 requires 表达式求值为 true 。
如果对于每个可能的模板实参,在 requires 表达式中都会发生替换失败,则程序非良构,不要求诊断:
template<class T> concept C = requires { new int[-(int)sizeof(T)]; // 对所有 T 均无效:格式错误,不要求诊断 };
如果 requires 表达式在其要求中包含无效类型或表达式,且未出现在 模板化实体 的声明中,则程序非良构。
局部参数
一个 requires 表达式可以通过 参数列表 引入局部参数。这些参数没有链接性、存储期或生存期;它们仅作为定义需求时使用的符号表示。
每个参数的类型确定方式与 确定函数参数实际类型 的方法相同:
template<typename T> concept C = requires(T p[2]) { (decltype(p))nullptr; // 正确:p 具有 T* 类型 };
若满足以下任一条件,则程序非良构:
- 局部参数具有 默认实参 。
- 参数列表以省略号结尾。
template<typename T> concept C1 = requires(T t = 0) // 错误:t 具有默认参数 { t; }; template<typename T> concept C2 = requires(T t, ...) // 错误:以省略号结尾 { t; };
简单要求
表达式
;
|
|||||||||
| 表达式 | - | 不以 requires 开头的表达式 |
一个简单的要求断言
expression
是有效的。
expression
是一个
unevaluated operand
。
template<typename T> concept Addable = requires (T a, T b) { a + b; // "表达式 “a + b” 是能够通过编译的有效表达式" }; template<class T, class U = T> concept Swappable = requires(T&& t, U&& u) { swap(std::forward<T>(t), std::forward<U>(u)); swap(std::forward<U>(u), std::forward<T>(t)); };
以关键字 requires 开头的要求始终被解释为嵌套要求。因此简单要求不能以未加括号的 requires 表达式开头。
类型要求
typename
标识符
;
|
|||||||||
| 标识符 | - | (可能被限定的) 标识符 (包括 简单模板标识符 ) |
类型要求断言由
identifier
命名的类型是有效的:这可用于验证某个具名嵌套类型是否存在,或验证类/别名模板特化是否命名了一个类型。命名类模板特化的类型要求不要求该类型是完整的。
template<typename T> using Ref = T&; template<typename T> concept C = requires { typename T::inner; // 需要嵌套成员名称 typename S<T>; // 需要类模板特化 typename Ref<T>; // 需要别名模板替换 {; template<class T, class U> using CommonType = std::common_type_t<T, U>; template<class T, class U> concept Common = requires (T&& t, U&& u) { typename CommonType<T, U>; // CommonType<T, U> 必须有效且命名一个类型 { CommonType<T, U>{std::forward<T>(t)} }; { CommonType<T, U>{std::forward<U>(u)} }; {;
复合需求
{
表达式
};
|
(1) | ||||||||
{
表达式
}
noexcept
;
|
(2) | ||||||||
{
表达式
} ->
类型约束
;
|
(3) | ||||||||
{
表达式
}
noexcept ->
类型约束
;
|
(4) | ||||||||
| expression | - | 表达式 |
| type-constraint | - | 约束 |
复合要求断言
表达式
的属性。替换和语义约束检查按以下顺序进行:
expression 是一个 unevaluated operand 。
template<typename T> concept C2 = requires(T x) { // 表达式 *x 必须有效 // 且类型 T::inner 必须存在 // 且 *x 的结果必须可转换为 T::inner {*x} -> std::convertible_to<typename T::inner>; // 表达式 x + 1 必须有效 // 且必须满足 std::same_as<decltype((x + 1)), int> // 即 (x + 1) 必须是 int 类型的纯右值 {x + 1} -> std::same_as<int>; // 表达式 x * 1 必须有效 // 且其结果必须可转换为 T {x * 1} -> std::convertible_to<T>; };
嵌套需求
requires
约束表达式
;
|
|||||||||
| constraint-expression | - | 表示 约束条件 的表达式 |
嵌套需求可用于根据局部参数指定额外约束。
约束表达式
必须满足被替换的模板参数(如果存在)。将模板参数代入嵌套需求时,仅会按需对
约束表达式
进行替换以确定其是否得到满足。
template<class T> concept Semiregular = DefaultConstructible<T> && CopyConstructible<T> && CopyAssignable<T> && Destructible<T> && requires(T a, std::size_t n) { requires Same<T*, decltype(&a)>; // 嵌套要求:"Same<...> 求值为 true" { a.~T() } noexcept; // 复合要求:"a.~T()" 是有效的表达式且不会抛出异常 requires Same<T*, decltype(new T)>; // 嵌套要求:"Same<...> 求值为 true" requires Same<T*, decltype(new T[n])>; // 嵌套要求 { delete new T }; // 复合要求 { delete new T[n] }; // 复合要求 };
注释
关键字 requires 也用于引入 requires 子句 。
template<typename T> concept Addable = requires (T x) { x + x; }; // requires 表达式 template<typename T> requires Addable<T> // requires 子句,非 requires 表达式 T add(T a, T b) { return a + b; } template<typename T> requires requires (T x) { x + x; } // 临时约束,注意关键字被使用了两次 T add(T a, T b) { return a + b; }
关键词
缺陷报告
以下行为变更缺陷报告被追溯应用于先前发布的C++标准。
| 缺陷报告 | 适用范围 | 发布时行为 | 正确行为 |
|---|---|---|---|
| CWG 2560 | C++20 | 未明确 requires 表达式中的参数类型是否被调整 | 同样需要调整 |
| CWG 2911 | C++20 |
出现在
requires
表达式中的所有表达式都是未求值操作数 |
仅部分
表达式是 |
参考文献
- C++23 标准 (ISO/IEC 14882:2024):
-
- 7.5.7 需求表达式 [expr.prim.req]
- C++20 标准 (ISO/IEC 14882:2020):
-
- 7.5.7 需求表达式 [expr.prim.req]
参见
| Constraints and concepts (C++20) | 指定模板参数的要求 |