|
| 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) |
0 commit comments