Skip to content

Commit 00fc718

Browse files
committed
C++29 : 「コルーチンのpromise型でreturn_valuereturn_voidの両方の宣言を許可」を追加 (close #1686)
1 parent 0dd78be commit 00fc718

5 files changed

Lines changed: 103 additions & 2 deletions

File tree

implementation-status.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@
366366
| P2434R5: [整数からポインタへの変換とポインタの由来の扱いを規定](/lang/cpp29/nondeterministic_pointer_provenance.md) | 整数からポインタへの変換では、その整数へ変換できるポインタ値のうち、プログラムの動作が定義される値が選択されると規定する | | | | |
367367
| P3347R6: [無効なポインタ値の読み書き・コピーを定義された動作とする](/lang/cpp29/invalid_pointer_operations.md) | 無効なポインタ値の使用のうち、間接参照は未定義動作、比較などは処理系定義のままとし、読み込み・書き込み・コピーなどそれ以外の操作を定義された動作とする | | | | |
368368
| P3658R1: [数学互換記法の文字を識別子として許可](/lang/cpp29/adjust_identifier_following_new_Unicode_recommendations.md) | Unicodeの新しい勧告に従い、`∇f```のような数学記法の文字(ID_Compat_Math_Start/Continueプロパティを持つ文字)を識別子に使用できるようにする | 17 | 16 | | |
369-
| P3950R1: [`return_value``return_void`は排他的ではない](/lang/cpp29/return_value_and_return_void_are_not_mutually_exclusive.md.nolink) | コルーチンの`promise`型が`return_value``return_void`の両方を持つことを許容する | | | | |
369+
| P3950R1: [コルーチンのpromise型で`return_value``return_void`の両方の宣言を許可](/lang/cpp29/return_value_and_return_void_are_not_mutually_exclusive.md) | 1つのコルーチン内に、値をともなう`co_return`文とともなわない`co_return`文を混在させられるようにする | | | | |
370370
| P3733R1: [名前付きユニバーサルキャラクタ名で使用できる別名を拡張](/lang/cpp29/more_named_universal_character_escapes.md) | `\N{…}`に指定できる文字名の別名の分類制限を撤廃し、`\N{NBSP}`のような略称 (abbreviation) なども使用できるようにする | 17 | 23 | | |
371371
| P3847R1: [ラムダ式のキャプチャが書かれた順に初期化されることを保証](/lang/cpp29/lexical_order_for_lambdas.md) | 明示的なキャプチャに対応するクロージャ型のメンバ変数が、キャプチャを書いた順に宣言・初期化され、逆順に破棄されることを保証する | Yes | Yes | | Yes |
372372
| P2243R0: [extern "C"の中でのテンプレートの宣言を許可](/lang/cpp29/language_linkage_for_templates.md) | テンプレートがC言語リンケージを持つことを禁止する規定を削除し、`extern "C"`の中でテンプレートを宣言できるようにする。C言語リンケージの関数ポインタ型を、テンプレートパラメータに依存する形で書けるようになる | | | | |

lang/cpp20/coroutines.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,8 @@ final-suspend :
196196

197197
Promise型のスコープにおいて、非修飾な`return_void`および`return_value`の探索が行われる。両方が見つかった場合、プログラムは不適格となる。
198198

199+
- C++29 : この制限は削除され、[両方を宣言できるようになった](/lang/cpp29/return_value_and_return_void_are_not_mutually_exclusive.md)
200+
199201
コルーチン呼び出しのglvalue結果またはprvalue結果オブジェクトを初期化するために、式 <code>_promise_</code>`.get_return_object()`が使われる。
200202
`get_return_object`呼び出しは高々1回であり、`initial_suspend`呼び出しよりも前に順序付けられる。
201203

@@ -622,6 +624,7 @@ C++20コルーチンに関するキーワードは、いずれも接頭辞`co_`
622624
## <a id="relative-page" href="#relative-page">関連項目</a>
623625
- C++20 [`<coroutine>`](/reference/coroutine.md)
624626
- C++23 [`<generator>`](/reference/generator.md)
627+
- [C++29 コルーチンのpromise型で`return_value``return_void`の両方の宣言を許可](/lang/cpp29/return_value_and_return_void_are_not_mutually_exclusive.md)
625628

626629

627630
## 参照

lang/cpp29.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ C++29とは、2029年中に改訂される予定の、C++バージョンの通
2323

2424
| 言語機能 | 説明 |
2525
|----------|------|
26-
| [`return_value``return_void`は排他的ではない](/lang/cpp29/return_value_and_return_void_are_not_mutually_exclusive.md.nolink) | コルーチンの`promise`型が`return_value``return_void`の両方を持つことを許容する |
26+
| [コルーチンのpromise型で`return_value``return_void`の両方の宣言を許可](/lang/cpp29/return_value_and_return_void_are_not_mutually_exclusive.md) | 1つのコルーチン内に、値をともなう`co_return`文とともなわない`co_return`文を混在させられるようにする |
2727

2828

2929
### 関数

lang/cpp29/feature_test_macros.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
|`__cpp_concepts`|`202606L`|[requires式の複合要件で条件付き`noexcept`指定を許可](conditional_noexcept_specifiers_in_compound_requirements.md)|
1919
|`__cpp_consteval`|`202606L`|[consteval-only型の規則をconsteval-only値の規則へ置き換え](consteval-only_values.md)|
2020
|`__cpp_contracts`|`202606L`|[仮想関数への事前条件・事後条件の指定を許可](contracts_for_virtual_functions.md)|
21+
|`__cpp_impl_coroutine`|`202606L`|[コルーチンのpromise型で`return_value``return_void`の両方の宣言を許可](return_value_and_return_void_are_not_mutually_exclusive.md)|
2122
|`__cpp_designated_initializers`|`202606L`|[基底クラスのメンバ変数に対する指示付き初期化を許可](designated-initializers_for_base_classes.md)|
2223
|`__cpp_named_character_escapes`|`202606L`|[名前付きユニバーサルキャラクタ名で使用できる別名を拡張](more_named_universal_character_escapes.md)|
2324
|`__cpp_pack_indexing`|`202606L`|[テンプレートテンプレートパラメータのパックへのインデックスアクセスを許可](pack_indexing_for_template_names.md)|
@@ -40,6 +41,8 @@
4041
## 参照
4142

4243
- [SD-FeatureTest: Feature-Test Macros and Policies - isocpp](https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations)
44+
- [P3950R1 `return_value` & `return_void` Are Not Mutually Exclusive](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3950r1.pdf)
45+
- C++29で`__cpp_impl_coroutine``202606L`に更新された
4346
- [P4101R1 Consteval-only Values for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4101r1.html)
4447
- C++29で`__cpp_consteval``202606L`に更新された
4548
- [P3540R3 `#embed` offset parameter](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3540r3.html)
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# コルーチンのpromise型で`return_value``return_void`の両方の宣言を許可 [P3950R1]
2+
* cpp29[meta cpp]
3+
4+
<!-- start lang caution -->
5+
6+
このページはC++29に採用された言語機能の変更を解説しています。
7+
8+
のちのC++規格でさらに変更される場合があるため[関連項目](#relative-page)を参照してください。
9+
10+
<!-- last lang caution -->
11+
12+
## 概要
13+
C++29では、コルーチンのpromise型が`return_value``return_void`の両方のメンバ関数を宣言できるようになる。これによって、1つのコルーチンの本体に、値をともなう`co_return v;`と値をともなわない`co_return;`の両方の文を書けるようになる。
14+
15+
```cpp
16+
task f(bool b) {
17+
if (b) {
18+
co_return 42; // promise.return_value(42)の呼び出し
19+
}
20+
co_return; // promise.return_void()の呼び出し
21+
}
22+
```
23+
24+
C++26までは、promise型のスコープでの名前`return_void`と`return_value`の探索が両方とも宣言を見つけた場合、プログラムは不適格と規定されていた。この制限は名前の探索にもとづいていたため、両方の関数が同時にオーバーロード解決可能になることがないよう制約 (`requires`) を付けた宣言であっても、宣言が存在するだけで不適格となり、ジェネリックなpromise型の実装方法を不必要に制限していた。
25+
26+
27+
## 仕様
28+
- promise型が`return_value`と`return_void`の両方を宣言した場合にプログラムを不適格とする規定が削除される
29+
- コルーチン本体の終端到達の規定が、名前探索ではなくオーバーロード解決にもとづいて定義し直される
30+
- `p.return_void()`のオーバーロード解決が成功する場合、コルーチン本体の終端到達はオペランドなしの`co_return`と等価である
31+
- そうでない場合、コルーチン本体の終端到達は未定義動作である
32+
- 機能テストマクロ`__cpp_impl_coroutine`の値が`202606L`に更新される
33+
34+
35+
## 例
36+
```cpp
37+
#include <coroutine>
38+
#include <iostream>
39+
40+
struct task {
41+
struct promise_type {
42+
task get_return_object() { return {}; }
43+
std::suspend_never initial_suspend() { return {}; }
44+
std::suspend_never final_suspend() noexcept { return {}; }
45+
void unhandled_exception() {}
46+
47+
// C++26までは、この2つを同時に宣言するとプログラムが不適格だった
48+
void return_void() {
49+
std::cout << "void" << std::endl;
50+
}
51+
void return_value(int x) {
52+
std::cout << "value: " << x << std::endl;
53+
}
54+
};
55+
};
56+
57+
task f(bool b) {
58+
if (b) {
59+
co_return 42;
60+
}
61+
co_return;
62+
}
63+
64+
int main() {
65+
f(true);
66+
f(false);
67+
}
68+
```
69+
* std::suspend_never[link /reference/coroutine/suspend_never.md]
70+
71+
このコードはC++29の規則のもとでは適格だが、2026年9月時点でこの変更を実装した処理系はない(GCC・Clang・MSVCのいずれも「promise型が`return_value``return_void`の両方を宣言している」というエラーになる)。
72+
73+
### 出力
74+
```
75+
value: 42
76+
void
77+
```
78+
79+
80+
## この機能が必要になった背景・経緯
81+
`return_value``return_void`の同時宣言の禁止は、コルーチンが導入される前の初期の提案(N4499)から存在していた規定である。初期の設計にはコルーチンの「最終的な型 (eventual type)」という概念があり、戻り値の型を1つに定める必要があったが、この概念は最終的な仕様からは削除されており、禁止だけが残っていた。
82+
83+
コルーチンの本体は通常の関数の本体とは異なり、promiseオブジェクトと対話するためのプロトコルへ書き換えられるものであるため、「関数の戻り値は1つの型で1通り」という通常の関数の性質に合わせる必然性はない。特にC++26で導入された[`std::execution`](/reference/execution.md)の完了シグネチャは、値をともなわない完了`set_value_t()`と値をともなう完了`set_value_t(T...)`の混在を表現できる。promise型はメンバ関数テンプレートによって複数の型の`co_return`を異なる完了シグネチャへ対応付けられるが、値をともなわない完了だけは`return_void`を宣言できないために特別なタグ型を受け取るといった回避策が必要で、コルーチンが`std::execution`の表現力に追いつけない状態だった。
84+
85+
同じ目的の提案(P1713R0)は2019年のケルン会議で合意に至らなかったが、`std::execution`の採用という新しい状況を受けて本提案が再提案され、採択された。
86+
87+
88+
## <a id="relative-page" href="#relative-page">関連項目</a>
89+
- [C++20 コルーチン](/lang/cpp20/coroutines.md)
90+
91+
92+
## 参照
93+
- [P3950R1 `return_value` & `return_void` Are Not Mutually Exclusive](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3950r1.pdf)
94+
- [P1713R0 Allowing both `co_return;` and `co_return value;` in the same coroutine](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1713r0.pdf)
95+
- 同じ目的の以前の提案。2019年のケルン会議で合意に至らなかった

0 commit comments

Comments
 (0)