1212## 概要
1313C++26では、制約式 (constraint) 内で使用される畳み込み式 (fold expression) に対して、包摂関係 (subsumption) の規則を導入する。
1414
15- C++23では、` (C<T> && ...) ` のような畳み込み式は構文上は連言 (conjunction) や選言 (disjunction) のように見えるが、制約の順序付けにおいては単一の原子制約 (atomic constraint) として扱われていた。そのため、概念的には一方がもう一方をより強く制約しているにもかかわらず、オーバーロード解決で曖昧になるケースがあった。
15+ C++23では、` (C<T> && ...) ` のような畳み込み式は制約の順序付けにおいて単一の原子制約 (atomic constraint) として扱われていた。そのため、概念的には一方がもう一方をより強く制約しているにもかかわらず、オーバーロード解決で曖昧になるケースがあった。
1616
1717``` cpp
1818template <class T >
@@ -39,19 +39,25 @@ g(std::vector{1, 2, 3});
3939* std::is_move_constructible_v[link /reference/type_traits/is_move_constructible.md]
4040* std::is_copy_constructible_v[link /reference/type_traits/is_copy_constructible.md]
4141
42- C++26では、`&&`による畳み込み式は個別の制約の連言として、`||`による畳み込み式は個別の制約の選言として正規化され、通常の原子制約と同じ包摂規則が適用される 。
42+ C++26では、制約の種類として新たに「折りたたみ展開制約 (fold expanded constraint)」が導入され、畳み込み式を含む制約の間で包摂関係が認識されるようになる 。
4343
4444
4545## 仕様
46- ### 畳み込み式の正規化
47- 畳み込み式が制約として使用される場合、以下のように正規化される:
46+ ### 折りたたみ展開制約 (fold expanded constraint)
47+ C++26では、制約の種類として連言 (conjunction)、選言 (disjunction)、原子制約 (atomic constraint) に加え、「折りたたみ展開制約 (fold expanded constraint)」(P2963R3) および「コンセプト依存制約 (concept-dependent constraint)」(P2841R7) が新たに導入される。ここでは折りたたみ展開制約について説明する。
4848
49- - `(C<T> && ...)` は `C<T1> && C<T2> && ... && C<Tn>` のような連言として扱われる
50- - `(C<T> || ...)` は `C<T1> || C<T2> || ... || C<Tn>` のような選言として扱われる
51- - `(... && C<T>)` や二項畳み込み式 `(init && ... && C<T>)` も同様に正規化される
49+ 畳み込み式 `(E && ...)` や `(E || ...)` が制約の正規化において処理される際、通常は折りたたみ展開制約として正規化される。折りたたみ展開制約は、制約`E`の正規形と畳み込み演算子 (`&&`または`||`) の組から構成される。
50+
51+ ただし、`E`が展開されていないコンセプトテンプレートパラメータパック (unexpanded concept template parameter pack) を含む場合は、そのパックの要素数`N`に基づいて`E_0 Op ... Op E_{N-1}`の形に展開され、連言または選言にまで分解される。これはP2841R7 (コンセプトテンプレートパラメータ) との連携による動作である。
5252
5353### 包摂の規則
54- 畳み込み式の制約間の包摂は、同じ畳み込み演算子 (`&&`または`||`) を使用している場合にのみ成立する。異なる畳み込み演算子間の包摂は行われない。
54+ 折りたたみ展開制約`A`がもうひとつの折りたたみ展開制約`B`を包摂するのは、以下の条件をすべて満たす場合である:
55+
56+ - `A`と`B`が包摂の互換性 (compatible for subsumption) をもつこと。すなわち、それぞれの制約が同等の展開されていないパックを含むこと
57+ - `A`と`B`が同じ畳み込み演算子 (`&&`または`||`) をもつこと
58+ - `A`の制約が`B`の制約を包摂すること
59+
60+ 異なる畳み込み演算子間の包摂は行われない。
5561
5662```cpp
5763template <class T>
@@ -64,20 +70,19 @@ template <class... T>
6470void f() requires (C<T> && ...); // #2
6571
6672// &&と||は異なる演算子なので、#2が#1を包摂するとはみなされない
67- // f()の呼び出しは曖昧
68- f();
73+ f(); // 曖昧
6974```
7075
7176### 短絡評価
72- 畳み込み式の制約の評価と充足 (satisfaction) は、通常の連言/選言と同様に短絡評価される。
77+ 折りたたみ展開制約の充足 (satisfaction) は、通常の連言/選言と同様に短絡評価される。 ` && ` の場合は充足されない最初の要素で、 ` || ` の場合は充足される最初の要素で評価が停止する 。
7378
7479
7580## この機能が必要になった背景・経緯
7681コンセプトと畳み込み式は、可変引数テンプレートの制約を簡潔に記述するために組み合わせて使われることが多い。しかし、C++23では畳み込み式が原子制約として扱われるため、概念的に明らかな包摂関係が認識されず、オーバーロード解決が曖昧になる問題があった。
7782
7883たとえば、[ ` std::ranges::bidirectional_range ` ] ( /reference/ranges/bidirectional_range.md ) と[ ` std::ranges::random_access_range ` ] ( /reference/ranges/random_access_range.md ) は非可変引数テンプレートでは正しく順序付けられるが、可変引数テンプレートで畳み込み式を使用すると順序付けが失われていた。この提案はその問題を解決する。
7984
80- この提案はP2841R0 (コンセプトと変数テンプレートのテンプレートテンプレートパラメータ) から派生したもので、畳み込み式のパターンが通常の制約式である場合を扱う。パターンがコンセプトテンプレートパラメータである場合はP2841で扱われる 。
85+ この提案はP2841R0から派生したもので、折りたたみ展開制約の導入と包摂規則を定める。畳み込み式のパターンにコンセプトテンプレートパラメータパック (P2841で導入) が含まれる場合は、連言/選言にまで完全に分解される 。
8186
8287
8388## <a id =" relative-page " href =" #relative-page " >関連項目</a >
0 commit comments