requires
表达式 (C++20 起)
生成一个描述约束的 bool 类型的纯右值表达式。
目录 |
[编辑] 语法
requires { requirement-seq } |
(1) | ||||||||
requires ( parameter-list (可选) ) { 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)]; // invalid for every T: ill-formed, no diagnostic required };
如果 requires 表达式在其需求中包含无效类型或表达式,并且它没有出现在模板化实体的声明中,则程序格式错误。
[编辑] 局部参数
一个 requires 表达式可以使用参数列表引入局部参数。这些参数没有链接、存储或生命周期;它们仅用作定义需求的符号。
每个参数的类型以与确定函数参数的实际类型相同的方式确定。
template<typename T> concept C = requires(T p[2]) { (decltype(p))nullptr; // OK, p has type T* };
如果满足以下任何条件,程序将不正确:
- 局部参数具有默认实参。
- 参数列表以省略号结尾。
template<typename T> concept C1 = requires(T t = 0) // Error: t has a default argument { t; }; template<typename T> concept C2 = requires(T t, ...) // Error: terminates with an ellipsis { t; };
[编辑] 简单需求
expression ; |
|||||||||
表达式 | - | 一个不以 requires 开头的表达式 |
一个简单需求断言 expression 是有效的。expression 是一个未求值操作数。
template<typename T> concept Addable = requires (T a, T b) { a + b; // "the expression “a + b” is a valid expression that will compile" }; 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 ; |
|||||||||
identifier | - | 一个(可能带限定的)标识符(包括简单模板标识符) |
类型需求断言由 identifier 命名的类型是有效的:这可以用于验证某个命名的嵌套类型是否存在,或者类/别名模板特化是否命名了一个类型。命名类模板特化的类型需求不要求类型是完整的。
template<typename T> using Ref = T&; template<typename T> concept C = requires { typename T::inner; // required nested member name typename S<T>; // required class template specialization typename Ref<T>; // required alias template substitution }; 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> is valid and names a type { CommonType<T, U>{std::forward<T>(t)} }; { CommonType<T, U>{std::forward<U>(u)} }; };
[编辑] 复合需求
{ expression }; |
(1) | ||||||||
{ expression } noexcept ; |
(2) | ||||||||
{ expression } -> type-constraint ; |
(3) | ||||||||
{ expression } noexcept -> type-constraint ; |
(4) | ||||||||
表达式 | - | 一个表达式 |
type-constraint | - | 一个约束 |
复合需求断言 expression 的属性。替换和语义约束检查按以下顺序进行:
expression 是一个未求值操作数。
template<typename T> concept C2 = requires(T x) { // the expression *x must be valid // AND the type T::inner must be valid // AND the result of *x must be convertible to T::inner {*x} -> std::convertible_to<typename T::inner>; // the expression x + 1 must be valid // AND std::same_as<decltype((x + 1)), int> must be satisfied // i.e., (x + 1) must be a prvalue of type int {x + 1} -> std::same_as<int>; // the expression x * 1 must be valid // AND its result must be convertible to T {x * 1} -> std::convertible_to<T>; };
[编辑] 嵌套需求
requires constraint-expression ; |
|||||||||
constraint-expression | - | 表示约束的表达式 |
嵌套需求可用于根据局部参数指定额外约束。constraint-expression 必须由替换的模板实参(如果有)满足。将模板实参替换到嵌套需求中,仅在确定 constraint-expression 是否满足所需的程度上,才会替换到 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)>; // nested: "Same<...> evaluates to true" { a.~T() } noexcept; // compound: "a.~T()" is a valid expression that doesn't throw requires Same<T*, decltype(new T)>; // nested: "Same<...> evaluates to true" requires Same<T*, decltype(new T[n])>; // nested { delete new T }; // compound { delete new T[n] }; // compound };
[编辑] 注意
关键词 requires 也用于引入requires 子句。
template<typename T> concept Addable = requires (T x) { x + x; }; // requires expression template<typename T> requires Addable<T> // requires clause, not requires expression T add(T a, T b) { return a + b; } template<typename T> requires requires (T x) { x + x; } // ad-hoc constraint, note keyword used twice 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 Requires 表达式 [expr.prim.req]
- C++20 标准 (ISO/IEC 14882:2020)
- 7.5.7 Requires 表达式 [expr.prim.req]
[编辑] 另请参阅
约束和概念(C++20) | 指定对模板实参的要求 |