Skip to content

Commit a6d6258

Browse files
committed
execution: with_awaitable_senders (#1384)
single-sender-value-type
1 parent 8b6a865 commit a6d6258

File tree

8 files changed

+326
-4
lines changed

8 files changed

+326
-4
lines changed

reference/execution/execution.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ Senderコンシューマは名前空間 `std::this_thread` で定義される。
152152
| 名前 | 説明 | 対応バージョン |
153153
|------|------|----------------|
154154
| [`execution::as_awaitable`](execution/as_awaitable.md.nolink) | Senderを[Awaitable型](/lang/cpp20/coroutines.md)へ変換 (customization point object) | C++26 |
155-
| [`execution::with_awaitable_senders`](execution/with_awaitable_senders.md.nolink) | [Promise型](/lang/cpp20/coroutines.md)の基底クラス (class template) | C++26 |
155+
| [`execution::with_awaitable_senders`](execution/with_awaitable_senders.md) | [Promise型](/lang/cpp20/coroutines.md)の基底クラス (class template) | C++26 |
156156
157157
158158
## バージョン

reference/execution/execution/read_env.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace std::execution {
1515
`read_env`は、非同期動作の[開始(start)](start.md)時に接続先[Receiver](receiver.md)の[環境](../queryable.md)に対して[クエリオブジェクト](../queryable.md)で問い合わせ、読み取った値を[値完了関数](set_value.md)で送信するSenderファクトリである。
1616
1717
クエリオブジェクトによるReceiver環境への問い合わせは`read_env`[Sender](sender.md)の構築時ではなく、Receiverと接続されたのち非同期動作が開始されるタイミングまで遅延される。
18-
[`let_value`](let_value.md)Senderアダプタと組み合わせたり、[Sender Awaitableなコルーチン](with_awaitable_senders.md.nolink)での`co_await`式によって、[Scheduler](get_scheduler.md)や[停止トークン](../get_stop_token.md)を読み取ることができる。
18+
[`let_value`](let_value.md)Senderアダプタと組み合わせたり、[Sender Awaitableなコルーチン](with_awaitable_senders.md)での`co_await`式によって、[Scheduler](get_scheduler.md)や[停止トークン](../get_stop_token.md)を読み取ることができる。
1919
2020
2121
## 効果

reference/execution/execution/sender_adaptor_closure.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace std::execution {
1010
struct sender_adaptor_closure { };
1111
}
1212
```
13+
* class-type[link class-type.md.nolink]
1314
1415
## 概要
1516
`sender_adaptor_closure`は、ユーザ定義のパイプ可能Senderアダプタクロージャオブジェクトの実装を補助するクラステンプレートである。
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# single-sender-value-type
2+
* execution[meta header]
3+
* type-alias[meta id-type]
4+
* std::execution[meta namespace]
5+
* cpp26[meta cpp]
6+
7+
```cpp
8+
template<class Sndr, class Env>
9+
using single-sender-value-type = see below; // exposition only
10+
```
11+
* see below[italic]
12+
13+
## 概要
14+
`single-sender-value-type`は、実行制御ライブラリの仕様定義で用いられる説明専用のエイリアステンプレートである。
15+
16+
型`Sndr`と`Env`に対して、`single-sender-value-type<Sndr, Env>`は下記のエイリアスとなる。
17+
18+
- [`value_types_of_t`](value_types_of_t.md)`<Sndr, Env,` [`decay_t`](/reference/type_traits/decay.md)`,` [`type_identity_t`](/reference/type_traits/type_identity.md)`>`が適格であるならば、その型。
19+
- そうではなく、[`value_types_of_t`](value_types_of_t.md)`<Sndr, Env,` [`tuple`](/reference/tuple/tuple.md)`,` [`variant`](/reference/variant/variant.md)`>`が`variant<tuple<>>`もしくは`variant<>`ならば、`void`型。
20+
- [`value_types_of_t`](value_types_of_t.md)`<Sndr, Env,` [`decayed-tuple`](decayed-tuple.md)`,` [`type_identity_t`](/reference/type_traits/type_identity.md)>`が適格であるならば、その型。
21+
- そうでなければ、`single-sender-value-type<Sndr, Env>`は不適格。
22+
23+
24+
## バージョン
25+
### 言語
26+
- C++26
27+
28+
29+
## 関連項目
30+
- [`execution::stopped_as_optional`](stopped_as_optional.md)
31+
- [`sender-awaitable`](sender-awaitable.md.nolink)
32+
33+
34+
## 参照
35+
- [P2300R10 `std::execution`](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2300r10.html)

reference/execution/execution/stopped_as_optional.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ transform_sender(get-domain-early(sndr), make-sender(stopped_as_optional, {}, sn
3030

3131

3232
### Senderアルゴリズムタグ `stopped_as_optional`
33-
説明用の式`sndr``env`に対して、型`Sndr``decltype((sndr))`、型`Env``decltype((env))`とする。[`sender-for`](sender-for.md)`<Sndr, stopped_as_optional_t> == false`、もしくは[`single-sender-value-type`](single-sender-value-type.md.nolink)`<Sndr, Env>`が不適格または`void`のとき、式`stopped_as_optional.transform_sender(sndr, env)`は不適格となる。
33+
説明用の式`sndr``env`に対して、型`Sndr``decltype((sndr))`、型`Env``decltype((env))`とする。[`sender-for`](sender-for.md)`<Sndr, stopped_as_optional_t> == false`、もしくは[`single-sender-value-type`](single-sender-value-type.md)`<Sndr, Env>`が不適格または`void`のとき、式`stopped_as_optional.transform_sender(sndr, env)`は不適格となる。
3434

3535
そうでなければ、式`stopped_as_optional.transform_sender(sndr, env)`は下記と等価。
3636

@@ -44,7 +44,7 @@ return let_stopped(
4444
}),
4545
[]() noexcept { return just(optional<V>()); });
4646
```
47-
* single-sender-value-type[link single-sender-value-type.md.nolink]
47+
* single-sender-value-type[link single-sender-value-type.md]
4848
* let_stopped[link let_stopped.md.nolink]
4949
* then[link then.md]
5050
* just[link just.md]
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
# with_awaitable_senders
2+
* execution[meta header]
3+
* class template[meta id-type]
4+
* std::execution[meta namespace]
5+
* cpp26[meta cpp]
6+
7+
```cpp
8+
namespace std::execution {
9+
template<class-type Promise>
10+
struct with_awaitable_senders {
11+
template<class OtherPromise>
12+
requires (!same_as<OtherPromise, void>)
13+
void set_continuation(coroutine_handle<OtherPromise> h) noexcept;
14+
15+
coroutine_handle<> continuation() const noexcept { return continuation; }
16+
17+
coroutine_handle<> unhandled_stopped() noexcept {
18+
return stopped-handler(continuation.address());
19+
}
20+
21+
template<class Value>
22+
see below await_transform(Value&& value);
23+
24+
private:
25+
[[noreturn]] static coroutine_handle<>
26+
default-unhandled-stopped(void*) noexcept { // exposition only
27+
terminate();
28+
}
29+
30+
coroutine_handle<> continuation{}; // exposition only
31+
coroutine_handle<> (*stopped-handler)(void*) noexcept = // exposition only
32+
&default-unhandled-stopped;
33+
};
34+
}
35+
```
36+
* class-type[link class-type.md.nolink]
37+
* terminate()[link /reference/exception/terminate.md]
38+
* coroutine_handle[link /reference/coroutine/coroutine_handle.md]
39+
* address()[link /reference/coroutine/coroutine_handle/address.md]
40+
* see below[italic]
41+
42+
## 概要
43+
`with_awaitable_senders`は、[コルーチンPromise型](/lang/cpp20/coroutines.md)の基底クラスとして利用することで、[Sender](sender.md)`co_await`演算子でAwait可能とするクラステンプレートである。
44+
45+
また`unhandled_stopped`のデフォルト実装を提供し、Senderが[`set_stopped`](set_stopped.md)を呼び出して停止完了したとき、Await式からキャッチできない "停止" 例外が送出されたかのように取り扱う。
46+
47+
48+
## メンバ関数
49+
50+
| 名前 | 説明 | 対応バージョン |
51+
|------|------|-------|
52+
| `(constructor)` | コンストラクタ | C++26 |
53+
| `(destructor)` | デストラクタ | C++26 |
54+
| [`set_continuation`](with_awaitable_senders/set_continuation.md) | 継続ハンドラを設定する | C++26 |
55+
| `continuation` | 継続ハンドラを返す | C++26 |
56+
| `unhandled_stopped` | 停止ハンドラを返す | C++26 |
57+
| [`await_transform`](with_awaitable_senders/await_transform.md) | [`co_await`演算子](/lang/cpp20/coroutines.md)へアダプトしAwaitableオブジェクトを返す | C++26 |
58+
59+
60+
## 静的メンバ関数
61+
62+
| 名前 | 説明 | 対応バージョン |
63+
|------|------|-------|
64+
| `default-unhandled-stopped` | 説明専用のデフォルト停止ハンドラ | C++26 |
65+
66+
67+
##
68+
```cpp example
69+
#include <coroutine>
70+
#include <print>
71+
#include <execution>
72+
namespace ex = std::execution;
73+
74+
template<typename T>
75+
class Lazy {
76+
public:
77+
struct promise_type;
78+
using value_type = T;
79+
using handle_type = std::coroutine_handle<promise_type>;
80+
81+
struct promise_type : ex::with_awaitable_senders<promise_type> {
82+
value_type value_;
83+
auto get_return_object() { return Lazy{handle_type::from_promise(*this)}; }
84+
auto initial_suspend() noexcept { return std::suspend_always{}; }
85+
auto final_suspend() noexcept { return std::suspend_always{}; }
86+
void unhandled_exception() { throw; }
87+
void return_value(value_type v) noexcept { value_ = v; }
88+
};
89+
90+
private:
91+
Lazy(handle_type h) : coro_{h} {}
92+
93+
public:
94+
Lazy(Lazy&& rhs)
95+
: coro_{std::exchange(rhs.coro_, nullptr)} {}
96+
Lazy& operator=(Lazy&& rhs) {
97+
if (coro_) { std::exchange(coro_, nullptr).destroy(); }
98+
std::swap(rhs.coro_, coro_);
99+
return *this;
100+
}
101+
~Lazy()
102+
{ if (coro_) { coro_.destroy(); } }
103+
104+
value_type get() {
105+
assert(coro_);
106+
if (!coro_.done()) {
107+
coro_.resume();
108+
}
109+
return coro_.promise().value_;
110+
}
111+
112+
private:
113+
handle_type coro_;
114+
};
115+
116+
// SenderをAwait可能なコルーチン
117+
Lazy<int> coro(int n)
118+
{
119+
std::println("coro start");
120+
ex::sender auto sndr =
121+
ex::just(n)
122+
| ex::then([](int m){ return m * 3; });
123+
124+
// Senderを開始して値取得を待機
125+
int val = co_await sndr;
126+
127+
std::println("coro end");
128+
co_return val * 7;
129+
}
130+
131+
int main()
132+
{
133+
try {
134+
auto task = coro(2);
135+
std::println("get");
136+
auto value = task.get();
137+
std::println("value={}", value);
138+
} catch (...) {
139+
std::println("<exception>");
140+
}
141+
}
142+
```
143+
* ex::with_awaitable_senders[color ff0000]
144+
* ex::sender[link sender.md]
145+
* ex::just[link just.md]
146+
* ex::then[link then.md]
147+
* std::coroutine_handle[link /reference/coroutine/coroutine_handle.md]
148+
* from_promise[link /reference/coroutine/coroutine_handle/from_promise.md]
149+
* destroy()[link /reference/coroutine/coroutine_handle/destroy.md]
150+
* done()[link /reference/coroutine/coroutine_handle/done.md]
151+
* resume()[link /reference/coroutine/coroutine_handle/resume.md]
152+
* promise()[link /reference/coroutine/coroutine_handle/promise.md]
153+
* std::suspend_always[link /reference/coroutine/suspend_always.md]
154+
155+
### 出力
156+
```
157+
get
158+
coro start
159+
coro end
160+
value=42
161+
```
162+
163+
164+
## バージョン
165+
### 言語
166+
- C++26
167+
168+
### 処理系
169+
- [Clang](/implementation.md#clang): ??
170+
- [GCC](/implementation.md#gcc): ??
171+
- [ICC](/implementation.md#icc): ??
172+
- [Visual C++](/implementation.md#visual_cpp): ??
173+
174+
175+
## 関連項目
176+
- [`execution::​as_awaitable`](​as_awaitable.md.nolink)
177+
- [コルーチン](/lang/cpp20/coroutines.md)
178+
179+
180+
## 参照
181+
- [P3325R5 A Utility for Creating Execution Environments](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3325r5.html)
182+
183+
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# await_transform
2+
* execution[meta header]
3+
* function template[meta id-type]
4+
* std::execution[meta namespace]
5+
* with_awaitable_senders[meta class]
6+
* cpp26[meta cpp]
7+
8+
```cpp
9+
template<class Value>
10+
call-result-t<as_awaitable_t, Value, Promise&>
11+
await_transform(Value&& value);
12+
```
13+
* call-result-t[link /reference/functional/call-result-t.md]
14+
* as_awaitable_t[link ../as_awaitable.md.nolink]
15+
16+
## 概要
17+
コルーチンの[`co_await`演算子](/lang/cpp20/coroutines.md)にアダプトし、[`as_awaitable`](../as_awaitable.md.nolink)で変換したAwaitableオブジェクトを返す。
18+
19+
20+
## 効果
21+
下記と等価。
22+
23+
```cpp
24+
return as_awaitable(std::forward<Value>(value), static_cast<Promise&>(*this));
25+
```
26+
* as_awaitable[link ../as_awaitable.md.nolink]
27+
28+
29+
## バージョン
30+
### 言語
31+
- C++26
32+
33+
### 処理系
34+
- [Clang](/implementation.md#clang): ??
35+
- [GCC](/implementation.md#gcc): ??
36+
- [ICC](/implementation.md#icc): ??
37+
- [Visual C++](/implementation.md#visual_cpp): ??
38+
39+
40+
## 関連項目
41+
- [`execution::as_awaitable`](../as_awaitable.md.nolink)
42+
43+
44+
## 参照
45+
- [P2300R10 `std::execution`](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2300r10.html)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# set_continuation
2+
* execution[meta header]
3+
* function template[meta id-type]
4+
* std::execution[meta namespace]
5+
* with_awaitable_senders[meta class]
6+
* cpp26[meta cpp]
7+
8+
```cpp
9+
template<class OtherPromise>
10+
requires (!same_as<OtherPromise, void>)
11+
void set_continuation(coroutine_handle<OtherPromise> h) noexcept;
12+
```
13+
* coroutine_handle[link /reference/coroutine/coroutine_handle.md]
14+
15+
## 概要
16+
継続処理のコルーチンハンドルを設定する。
17+
18+
19+
## テンプレートパラメータ制約
20+
`!`[`same_as`](/reference/concepts/same_as.md)`<OtherPromise, void>`
21+
22+
23+
## 効果
24+
下記と等価。
25+
26+
```cpp
27+
continuation = h;
28+
if constexpr ( requires(OtherPromise& other) { other.unhandled_stopped(); } ) {
29+
stopped-handler = [](void* p) noexcept -> coroutine_handle<> {
30+
return coroutine_handle<OtherPromise>::from_address(p)
31+
.promise().unhandled_stopped();
32+
};
33+
} else {
34+
stopped-handler = &default-unhandled-stopped;
35+
}
36+
```
37+
* coroutine_handle[link /reference/coroutine/coroutine_handle.md]
38+
* from_address[link /reference/coroutine/coroutine_handle/from_address.md]
39+
* promise()[link /reference/coroutine/coroutine_handle/promise.md]
40+
41+
42+
## 例外
43+
投げない
44+
45+
46+
## バージョン
47+
### 言語
48+
- C++26
49+
50+
### 処理系
51+
- [Clang](/implementation.md#clang): ??
52+
- [GCC](/implementation.md#gcc): ??
53+
- [ICC](/implementation.md#icc): ??
54+
- [Visual C++](/implementation.md#visual_cpp): ??
55+
56+
57+
## 参照
58+
- [P2300R10 `std::execution`](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2300r10.html)

0 commit comments

Comments
 (0)