requires
expression
(since C++20)
制約を記述する 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
の特性を主張します。置換と意味制約のチェックは以下の順序で進行します:
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; }
キーワード
不具合報告
以下の動作変更の欠陥報告書は、以前に公開された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) | テンプレート引数に対する要件を指定する |