requires 式 (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)]; // 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++標準に遡って適用されました。
| 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 standard (ISO/IEC 14882:2020)
- 7.5.7 Requires 式 [expr.prim.req]
[編集] 関連項目
| 制約とコンセプト(C++20) | テンプレート引数に関する要件を指定します |