命名空间
变体
操作

需要表达式 (从 C++20 开始)

来自 cppreference.com
< cpp‎ | 语言
 
 
C++ 语言
表达式
替代表示
字面量
布尔值 - 整数 - 浮点数
字符 - 字符串 - nullptr (C++11)
用户定义的 (C++11)
实用程序
属性 (C++11)
类型
typedef 声明
类型别名声明 (C++11)
强制转换
内存分配
特定于类的函数属性
explicit (C++11)
static

特殊成员函数
模板
其他
 
 
 
 

生成类型为 bool 的 prvalue 表达式,该表达式描述了约束条件。

内容

[编辑] 语法

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

[编辑] 需求

[编辑] 简单需求

简单需求是一个任意表达式语句,它不以关键字requires开头。它断言该表达式是有效的。表达式是一个未经评估的操作数;仅检查语言正确性。

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后跟一个类型名称,可选地进行限定。该需求是命名类型是有效的:这可用于验证是否存在某个命名的嵌套类型,或类模板特化是否命名一个类型,或别名模板特化是否命名一个类型。命名类模板特化的类型需求不需要类型是完整的。

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 } noexcept(可选) return-type-requirement (可选) ;
return-type-requirement - -> type-constraint

并断言命名表达式的属性。代入和语义约束检查按以下顺序进行

1) 将模板参数(如果有)代入expression
2) 如果使用noexcept,则expression不能可能抛出异常
3) 如果存在return-type-requirement,则
a) 将模板参数代入return-type-requirement ;
b) decltype((expression))必须满足type-constraint强加的约束。否则,封闭的 requires 表达式为false.
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是否满足。

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 表达式中是否调整参数类型 也调整

[编辑] 参考文献

  • 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) 指定对模板参数的要求[编辑]