命名空间
变体
操作

requires 表达式 (C++20 起)

来自 cppreference.cn
< cpp‎ | language
 
 
C++ 语言
通用主题
流程控制
条件执行语句
if
迭代语句(循环)
for
范围 for (C++11)
跳转语句
函数
函数声明
Lambda 函数表达式
inline 说明符
动态异常规范 在 C++17 中弃用*
noexcept 说明符 (C++11)
异常
命名空间
类型
说明符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
存储期说明符
初始化
 
 
 
 

产生描述约束的 bool 类型的 prvalue 表达式。

内容

[编辑] 语法

requires { requirement-seq } (1)
requires ( parameter-list (可选) ) { requirement-seq } (2)
parameter-list - 形参列表
requirement-seq - requirement 序列,每个 requirement 是下列之一

[编辑] 解释

要求可以引用作用域内的模板形参、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 ;
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)
expression - 表达式
type-constraint - 约束


复合要求断言 expression 的属性。替换和语义约束检查按以下顺序进行

1) 模板实参(如果有)被替换到 expression 中。
2) 如果存在 noexcept,则 expression 必须不是潜在抛出的
3) 如果存在 type-constraint,则
a) 模板实参被替换到 type-constraint 中。
b) decltype((expression )) 必须满足 type-constraint 施加的约束。否则,外围 requires 表达式为 false

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; }

[编辑] 关键字

requires

[编辑] 缺陷报告

以下行为变更缺陷报告已追溯应用于先前发布的 C++ 标准。

DR 应用于 已发布行为 正确行为
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) 指定对模板实参的要求[编辑]