Namespaces
Variants

requires expression (since C++20)

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

制約を記述する 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)]; // すべてのTに対して無効:不正形式、診断不要
};

requires式がその要件内に無効な型または式を含み、かつそれが テンプレート化されたエンティティ の宣言内に現れない場合、プログラムは不適格となる。

ローカルパラメータ

requires 式は、 パラメータリスト を使用してローカルパラメータを導入できます。これらのパラメータはリンケージ、ストレージ、または寿命を持たず、要件を定義するための表記法としてのみ使用されます。

各パラメータの型は、 関数パラメータの実際の型を決定する 方法と同じ方法で決定されます:

template<typename T>
concept C = requires(T p[2])
{
    (decltype(p))nullptr; // OK、pはT*型を持つ
};

以下のいずれかの条件が満たされる場合、プログラムは不適格となります:

  • ローカルパラメータが デフォルト引数 を持っている。
  • パラメータリストが省略記号で終了している。
template<typename T>
concept C1 = requires(T t = 0)  // エラー: tがデフォルト引数を持っています
{
    t;
};
template<typename T>
concept C2 = requires(T t, ...) // エラー: 省略記号で終了しています
{
    t;
};

シンプルな要件

;
expression - 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 ;
identifier - (修飾されている可能性のある) identifier simple template identifier を含む)


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 の特性を主張します。置換と意味制約のチェックは以下の順序で進行します:

1) テンプレート引数(存在する場合)は expression に代入されます。
2) noexcept が指定されている場合、 expression 例外を投げる可能性があってはならない
3) type-constraint が存在する場合:
a) テンプレート引数は type-constraint に代入されます。
b) decltype ( ( expression  ) ) type-constraint によって課せられた制約を満たさなければならない。そうでない場合、外側の requires 式は false となる。

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 型のprvalueでなければならない
    {x + 1} -> std::same_as<int>;
    // 式 x * 1 が有効でなければならない
    // かつその結果が 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)>; // ネスト要件: "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; } // アドホック制約(キーワードが2回使用されていることに注意)
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) テンプレート引数に対する要件を指定する