Skip to content

Commit 7160b82

Browse files
committed
execution: let_value (#1384)
1 parent 01eff31 commit 7160b82

11 files changed

Lines changed: 318 additions & 13 deletions

File tree

reference/execution/execution.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,9 @@ namespace std::execution {
118118
| [`execution::then`](execution/then.md) | 値完了時の継続処理をアタッチ (customization point object) | C++26 |
119119
| [`execution::upon_error`](execution/upon_error.md.nolink) | エラー完了時の継続処理をアタッチ (customization point object) | C++26 |
120120
| [`execution::upon_stopped`](execution/upon_stopped.md.nolink) | 停止完了時の継続処理をアタッチ (customization point object) | C++26 |
121-
| [`execution::let_value`](execution/let_value.md.nolink) | 値完了の継続にユーザ定義処理を連結 (customization point object) | C++26 |
122-
| [`execution::let_error`](execution/let_error.md.nolink) | エラー完了の継続にユーザ定義処理を連結 (customization point object) | C++26 |
123-
| [`execution::let_stopped`](execution/let_stopped.md.nolink) | 停止完了の継続にユーザ定義処理を連結 (customization point object) | C++26 |
121+
| [`execution::let_value`](execution/let_value.md) | 値完了結果から入れ子の非同期操作へ変換 (customization point object) | C++26 |
122+
| [`execution::let_error`](execution/let_error.md.nolink) | エラー完了結果から入れ子の非同期操作へ変換 (customization point object) | C++26 |
123+
| [`execution::let_stopped`](execution/let_stopped.md.nolink) | 停止完了を入れ子の非同期操作へ変換 (customization point object) | C++26 |
124124
| [`execution::bulk`](execution/bulk.md.nolink) | インデクス空間上で指定関数を連続実行 (customization point object) | C++26 |
125125
| [`execution::split`](execution/split.md.nolink) | 入力Senderの値を複製送信 (customization point object) | C++26 |
126126
| [`execution::when_all`](execution/when_all.md.nolink) | 全ての入力Sender完了を待機 (customization point object) | C++26 |

reference/execution/execution/connect.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ namespace std::execution {
112112
`V``await-result-type<DS, connect-awaitable-promise>`とする。
113113

114114
`SET-VALUE-SIG(T)`を、`T`がCV修飾された`void`ならば[`set_value_t`](set_value.md)`()`型、そうでなければ[`set_value_t`](set_value.md)`(T)`型とする。
115-
`Sigs`を次の通り定義する
115+
`Sigs`を下記の通り定義する
116116

117117
```cpp
118118
completion_signatures<

reference/execution/execution/default_domain/apply_sender.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Senderアルゴリズム適用のデフォルト動作。
2121
2222
2323
## テンプレートパラメータ制約
24-
説明用の式`e`を`Tag().apply_sender(`[`std::forward`](/reference/utility/forward.md)`<Sndr>(sndr), `[`std::forward`](/reference/utility/forward.md)`<Args>(args)...)`としたとき、式`e`が適格であること。
24+
説明用の式`e`を`Tag().apply_sender(`[`std::forward`](/reference/utility/forward.md)`<Sndr>(sndr),` [`std::forward`](/reference/utility/forward.md)`<Args>(args)...)`としたとき、式`e`が適格であること。
2525
2626
2727
## 戻り値
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# emplace-from
2+
* execution[meta header]
3+
* std::execution[meta namespace]
4+
* class template[meta id-type]
5+
* cpp26[meta cpp]
6+
7+
```cpp
8+
template<callable Fun>
9+
requires is_nothrow_move_constructible_v<Fun>
10+
struct emplace-from {
11+
Fun fun; // exposition only
12+
using type = call-result-t<Fun>;
13+
14+
constexpr operator type() && noexcept(nothrow-callable<Fun>) {
15+
return std::move(fun)();
16+
}
17+
18+
constexpr type operator()() && noexcept(nothrow-callable<Fun>) {
19+
return std::move(fun)();
20+
}
21+
};
22+
```
23+
* is_nothrow_move_constructible_v[link /reference/type_traits/is_nothrow_move_constructible.md]
24+
* call-result-t[link call-result-t.md.nolink]
25+
* nothrow-callable[link /reference/functional/nothrow-callable.md.nolink]
26+
* std::move[link /reference/utility/move.md]
27+
28+
## 概要
29+
`emplace-from`は、Senderアルゴリズム動作仕様定義で用いられる説明専用のクラステンプレートである。
30+
31+
32+
## バージョン
33+
### 言語
34+
- C++26
35+
36+
## 関連項目
37+
- [`execution::let_value`](let_value.md)
38+
39+
40+
## 参照
41+
- [P2300R10 `std::execution`](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2300r10.html)

reference/execution/execution/get-domain-early.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ constexpr auto get-domain-early(const Sndr& sndr) noexcept;
1212
## 概要
1313
[Sender](sender.md)アルゴリズム構築時のカスタマイゼーションポイントとして、[実行ドメイン](default_domain.md)を取得する説明専用の関数テンプレート。
1414

15-
下記の優先順で実行ドメインを検索し、最初に妥当となる型を採用する
15+
下記の優先順で実行ドメインを検索し、最初に適格となる型を採用する
1616

1717
- Senderの[属性](../queryable.md)の実行ドメイン
1818
- Senderの[完了Scheduler](get_completion_scheduler.md)の実行ドメイン
1919
- [デフォルト実行ドメイン](default_domain.md)
2020

2121

2222
## 効果
23-
説明用の型`Domain`を下記リストのうち最初に妥当となる式の型と定義したとき`return Doamin();`と等価。
23+
説明用の型`Domain`を下記リストのうち最初に適格となる式の型と定義したとき`return Doamin();`と等価。
2424

2525
- [`get_domain`](get_domain.md)`(`[`get_env`](get_env.md)`(sndr))`
2626
- [`completion-domain`](completion-domain.md)`(sndr)`

reference/execution/execution/get-domain-late.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ constexpr auto get-domain-late(const Sndr& sndr, const Env& env) noexcept;
1212
## 概要
1313
[Sender](sender.md)と[Receiver](receiver.md)間[接続(connect)](connect.md)時のカスタマイゼーションポイントとして、[実行ドメイン](default_domain.md)を取得する説明専用の関数テンプレート。
1414
15-
下記の優先順で実行ドメインを検索し、最初に妥当となる型を採用する
15+
下記の優先順で実行ドメインを検索し、最初に適格となる型を採用する
1616
(Senderアルゴリズム[`continue_on`](continue_on.md.nolink)のみ引数に指定した[Scheduler](scheduler.md)から取得。)
1717
1818
- Senderの[属性](../queryable.md)の実行ドメイン
@@ -37,7 +37,7 @@ constexpr auto get-domain-late(const Sndr& sndr, const Env& env) noexcept;
3737
* get_domain[link get_domain.md]
3838
* default_domain()[link default_domain.md]
3939
40-
- それ以外のとき、下記リストのうち最初に妥当となる式の型、かつ`void`ではない型とする。
40+
- それ以外のとき、下記リストのうち最初に適格となる式の型、かつ`void`ではない型とする。
4141
- [`get_domain`](get_domain.md)`(`[`get_env`](get_env.md)`(sndr))`
4242
- [`completion-domain<void>`](completion-domain.md)`(sndr)`
4343
- [`get_domain`](get_domain.md)`(env)`

reference/execution/execution/into_variant.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ namespace std::execution {
8585
8686
8787
## カスタマイゼーションポイント
88-
Senderアルゴリズム構築時に、入力[Sender](sender.md)`sndr`に[関連付けられた実行ドメイン](get-domain-early.md)に対して[`execution::transform_sender`](transform_sender.md)経由でSender変換が行われる。
88+
Senderアルゴリズム構築時および[Receiver](receiver.md)接続時に、関連付けられた実行ドメインに対して[`execution::transform_sender`](transform_sender.md)経由でSender変換が行われる。
8989
[デフォルト実行ドメイン](../execution/default_domain.md)では無変換。
9090
9191
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
# let_value
2+
* execution[meta header]
3+
* cpo[meta id-type]
4+
* std::execution[meta namespace]
5+
* cpp26[meta cpp]
6+
7+
```cpp
8+
namespace std::execution {
9+
struct let_value_t { unspecified };
10+
inline constexpr let_value_t let_value{};
11+
}
12+
```
13+
* unspecified[italic]
14+
15+
## 概要
16+
`let_value`は、新しいSenderを返す関数呼び出し可能なオブジェクトに引き渡すことで、入力[Sender](sender.md)の[値完了](set_value.md)結果から子入れ子の非同期操作へと変換するSenderアダプタである。
17+
18+
`let_value`はパイプライン記法をサポートする。
19+
20+
21+
## 効果
22+
説明用の式`sndr`と`f`に対して、`decltype((sndr))`が[`sender`](sender.md)を満たさない、もしくは[`movable-value`](../movable-value.md)を満たさないとき、呼び出し式`let_value(sndr, f)`は不適格となる。
23+
24+
そうでなければ、呼び出し式`let_value(sndr, f)`は`sndr`が1回だけ評価されることを除いて、下記と等価。
25+
26+
```cpp
27+
transform_sender(get-domain-early(sndr), make-sender(let_value, f, sndr))
28+
```
29+
* transform_sender[link transform_sender.md]
30+
* get-domain-early[link get-domain-early.md]
31+
* make-sender[link make-sender.md]
32+
33+
34+
### Senderアルゴリズムタグ `let_value`
35+
Senderアルゴリズム動作説明用のクラステンプレート[`impls-for`](impls-for.md)に対して、下記の特殊化が定義される。
36+
37+
```cpp
38+
namespace std::execution {
39+
template<>
40+
struct impls-for<decayed-typeof<let_value>> : default-impls {
41+
static constexpr auto get-state = see below;
42+
static constexpr auto complete = see below;
43+
};
44+
}
45+
```
46+
* impls-for[link impls-for.md]
47+
* default-impls[link impls-for.md]
48+
* decayed-typeof[link decayed-typeof.md.nolink]
49+
* see below[italic]
50+
51+
`impls-for<decayed-typeof<let_value>>::get-state`メンバは、下記ラムダ式と等価な関数呼び出し可能なオブジェクトで初期化される。
52+
53+
```cpp
54+
[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) requires see below {
55+
auto& [_, fn, child] = sndr;
56+
using fn_t = decay_t<decltype(fn)>;
57+
using env_t = decltype(let-env(child));
58+
using args_variant_t = see below;
59+
using ops2_variant_t = see below;
60+
61+
struct state-type {
62+
fn_t fn; // exposition only
63+
env_t env; // exposition only
64+
args_variant_t args; // exposition only
65+
ops2_variant_t ops2; // exposition only
66+
};
67+
return state-type{std::forward_like<Sndr>(fn), let-env(child), {}, {}};
68+
}
69+
```
70+
* decay_t[link /reference/type_traits/decay.md]
71+
* see below[italic]
72+
73+
- 説明用のパック`Sigs`[`completion_signatures_of_t`](completion_signatures_of_t.md)`<`[`child-type`](child-type.md)`<Sndr>,` [`env_of_t`](env_of_t.md)`<Rcvr>>`による[`completion_signatures`](completion_signatures.md)特殊化のテンプレートパラメータとし、パック`LetSigs``Sigs`に含まれる型のうち戻り値型が`decayed-typeof<`[`set_value`](set_value.md)`>`に等しいものと定義する。説明用のエイリアステンプレート`as-tuple<Tag(Args...)>`[`decayed-tuple`](decayed-tuple.md)`<Args...>`と定義する。型`args_variant_t`は下記定義において重複削除した型となる。
74+
75+
```cpp
76+
variant<monostate, as-tuple<LetSigs>...>
77+
```
78+
* variant[link /reference/variant/variant.md]
79+
* monostate[link /reference/variant/monostate.md]
80+
81+
- 説明用の型`Tag`とパック`Args`に対して、説明用のエイリアステンプレート`as-sndr2<Tag(Args...)>`を`call-result-t<Fn,` [`decay_t`](/reference/type_traits/decay.md)`<Arg>&...>`と定義する。型`ops2_variant_t`は下記定義において重複削除した型となる。
82+
83+
```cpp
84+
variant<monostate, connect_result_t<as-sndr2<LetSigs>, receiver2<Rcvr, Env>>...>
85+
```
86+
* variant[link /reference/variant/variant.md]
87+
* monostate[link /reference/variant/monostate.md]
88+
* connect_result_t[link connect_result_t.md]
89+
90+
- 型`args_variant_t`および`ops2_variant_t`が適格なときに限って、上記ラムダ式のrequires節が満たされる。
91+
92+
`impls-for<decayed-typeof<let_value>>::complete`メンバは、下記ラムダ式と等価な関数呼び出し可能なオブジェクトで初期化される。
93+
94+
```cpp
95+
[]<class Tag, class... Args>
96+
(auto, auto& state, auto& rcvr, Tag, Args&&... args) noexcept -> void {
97+
if constexpr (same_as<Tag, decayed-typeof<set_value>>) {
98+
TRY-EVAL(rcvr, let-bind(state, rcvr, std::forward<Args>(args)...));
99+
} else {
100+
Tag()(std::move(rcvr), std::forward<Args>(args)...);
101+
}
102+
}
103+
```
104+
* set_value[link set_value.md]
105+
* decayed-typeof[link decayed-typeof.md.nolink]
106+
* std::move[link /reference/utility/move.md]
107+
108+
説明用の式`sndr`と`env`に対して、型`Sndr`を`decltype((sndr))`とする。[`sender-for`](sender-for.md)`<Sndr, decayed-typeof<let_value>> == false`のとき、式`let_value.transform_env(sndr, env)`は不適格となる。
109+
110+
そうでなければ、式`let_value.transform_env(sndr, env)`は[`JOIN-ENV`](JOIN-ENV.md.nolink)`(let-env(sndr),` [`FWD-ENV`](../forwarding_query.md)`(env))`と等価。
111+
112+
113+
## 説明専用エンティティ
114+
説明用の式`sndr`を用いて、`let-env(sndr)`を下記リストのうち最初に適格となる式と定義する。
115+
116+
- [`SCHED-ENV`](SCHED-ENV.md.nolink)`(`[`get_completion_scheduler`](get_completion_scheduler.md)`<decayed-typeof<`[`set_value`](set_value.md)`>>(`[`get_env`](get_env.md)`(sndr)))`
117+
- [`MAKE-ENV`](MAKE-ENV.md.nolink)`(`[`get_domain`](get_domain.md)`,` [`get_domain`](get_domain.md)`(`[`get_env`](get_env.md)`(sndr)))`
118+
- `(void(sndr),` [`env<>{}`](env.md)`)`
119+
120+
```cpp
121+
namespace std::execution {
122+
template<class State, class Rcvr, class... Args>
123+
void let-bind(State& state, Rcvr& rcvr, Args&&... args); // exposition only
124+
}
125+
```
126+
127+
説明専用の`let-bind`テンプレート関数の効果は下記と等価。
128+
129+
```cpp
130+
using args_t = decayed-tuple<Args...>;
131+
auto mkop2 = [&] {
132+
return connect(
133+
apply(std::move(state.fn),
134+
state.args.template emplace<args_t>(std::forward<Args>(args)...)),
135+
receiver2{rcvr, std::move(state.env)});
136+
};
137+
start(state.ops2.template emplace<decltype(mkop2())>(emplace-from{mkop2}));
138+
```
139+
* decayed-tuple[link decayed-tuple.md]
140+
* connect[link connect.md]
141+
* start[link start.md]
142+
* emplace-from[link emplace-from.md]
143+
* apply[link /reference/tuple/apply.md]
144+
* template emplace[link /reference/variant/variant/emplace.md]
145+
* std::move[link /reference/utility/move.md]
146+
147+
説明専用のテンプレートクラス`receiver2`を下記の通り定義する。
148+
149+
```cpp
150+
namespace std::execution {
151+
template<class Rcvr, class Env>
152+
struct receiver2 {
153+
using receiver_concept = receiver_t;
154+
155+
template<class... Args>
156+
void set_value(Args&&... args) && noexcept {
157+
execution::set_value(std::move(rcvr), std::forward<Args>(args)...);
158+
}
159+
160+
template<class Error>
161+
void set_error(Error&& err) && noexcept {
162+
execution::set_error(std::move(rcvr), std::forward<Error>(err));
163+
}
164+
165+
void set_stopped() && noexcept {
166+
execution::set_stopped(std::move(rcvr));
167+
}
168+
169+
decltype(auto) get_env() const noexcept {
170+
return see below;
171+
}
172+
173+
Rcvr& rcvr; // exposition only
174+
Env env; // exposition only
175+
};
176+
}
177+
```
178+
* receiver_t[link receiver.md]
179+
* execution::set_value[link set_value.md]
180+
* execution::set_error[link set_error.md]
181+
* execution::set_stopped[link set_stopped.md]
182+
* std::move[link /reference/utility/move.md]
183+
* see below[italic]
184+
185+
メンバ関数`receiver2::get_env`の呼び出しは、下記を満たすオブジェクト`e`を返す。
186+
187+
-`decltype(e)`[`queryable`](../queryable.md)のモデルであり、かつ
188+
- 与えられた[クエリオブジェクト](../queryable.md)`q`に対して、式`e.query(q)`は式`env.query(q)`が有効ならばその式と等価。そうでなければ、式`e.query(q)`[`get_env`](get_env.md)`(rcvr).query(q)`と等価。
189+
190+
191+
## カスタマイゼーションポイント
192+
Senderアルゴリズム構築時および[Receiver](receiver.md)接続時に、関連付けられた実行ドメインに対して[`execution::transform_sender`](transform_sender.md)経由でSender変換が行われる。
193+
[デフォルト実行ドメイン](../execution/default_domain.md)では無変換。
194+
195+
196+
説明用の式`out_sndr``let_value(sndr, f)`の戻り値[Sender](sender.md)とし、式`rcvr`を式[`connect`](connect.md)`(out_sndr, rcvr)`が適格となる[Receiver](receiver.md)とする。式[`connect`](connect.md)`(out_sndr, rcvr)`[開始(start)](start.md)時に下記を満たす非同期操作を生成しない場合、動作は未定義となる。
197+
198+
- 入力[Sender](sender.md)`sndr`の完了結果で[`set_value`](set_value.md)が呼ばれるとき、`f`を呼び出すこと。
199+
- 非同期操作の完了は、`f`が返すSenderの完了に依存すること。
200+
- `sndr`により送信された他完了操作を伝搬すること。
201+
202+
203+
##
204+
```cpp example
205+
#include <print>
206+
#include <execution>
207+
namespace ex = std::execution;
208+
209+
int main()
210+
{
211+
{ // 関数呼び出し
212+
ex::sender snd0 = ex::just(21);
213+
ex::sender snd1 = ex::let_value(
214+
snd0,
215+
[](int n) -> ex::sender auto {
216+
return ex::just(n * 2);
217+
});
218+
auto [val] = std::this_thread::sync_wait(snd1).value();
219+
std::println("{}", val);
220+
}
221+
222+
{ // パイプライン記法
223+
ex::sender sndr = ex::just(21)
224+
| ex::let_value(
225+
[](int n) -> ex::sender auto {
226+
return ex::just(n * 2);
227+
});
228+
auto [val] = std::this_thread::sync_wait(sndr).value();
229+
std::println("{}", val);
230+
}
231+
}
232+
```
233+
* ex::let_value[color ff0000]
234+
* ex::sender[link sender.md]
235+
* ex::just[link just.md]
236+
* std::this_thread::sync_wait[link ../this_thread/sync_wait.md]
237+
* value()[link /reference/optional/optional/value.md]
238+
239+
### 出力
240+
```
241+
42
242+
42
243+
```
244+
245+
246+
## バージョン
247+
### 言語
248+
- C++26
249+
250+
### 処理系
251+
- [Clang](/implementation.md#clang): ??
252+
- [GCC](/implementation.md#gcc): ??
253+
- [ICC](/implementation.md#icc): ??
254+
- [Visual C++](/implementation.md#visual_cpp): ??
255+
256+
257+
## 関連項目
258+
- [`execution::let_error`](let_error.md.nolink)
259+
- [`execution::let_stopped`](let_stopped.md.nolink)
260+
261+
262+
## 参照
263+
- [P2999R3 Sender Algorithm Customization](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2999r3.html)
264+
- [P2300R10 `std::execution`](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2300r10.html)

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.nolink)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.nolink)での`co_await`式によって、[Scheduler](get_scheduler.md)や[停止トークン](../get_stop_token.md)を読み取ることができる。
1919
2020
2121
## 効果

0 commit comments

Comments
 (0)