Skip to content

Commit e411c3d

Browse files
committed
execution: into_variant (#1384)
child-type
1 parent a2c9f2f commit e411c3d

4 files changed

Lines changed: 226 additions & 4 deletions

File tree

reference/execution/execution.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ namespace std::execution {
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 |
127127
| [`execution::when_all_with_variant`](execution/when_all_with_variant.md.nolink) | 複数の値完了シグネチャをもつ全ての入力Sender完了を待機 (customization point object) | C++26 |
128-
| [`execution::into_variant`](execution/into_variant.md.nolink) | 複数の値完了シグネチャを単一[`variant`](/reference/variant/variant.md)型の値完了シグネチャに変換 (customization point object) | C++26 |
128+
| [`execution::into_variant`](execution/into_variant.md) | 複数の値完了シグネチャを単一[`variant`](/reference/variant/variant.md)型の値完了シグネチャに変換 (customization point object) | C++26 |
129129
| [`execution::stopped_as_optional`](execution/stopped_as_optional.md.nolink) | 入力Senderの停止完了を[`optional`](/reference/optional/optional.md)型の値完了に変換 (customization point object) | C++26 |
130130
| [`execution::stopped_as_error`](execution/stopped_as_error.md.nolink) | 入力Senderの停止完了をエラー完了に変換 (customization point object) | C++26 |
131131
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# child-type
2+
* execution[meta header]
3+
* std::execution[meta namespace]
4+
* type-alias[meta id-type]
5+
* cpp26[meta cpp]
6+
7+
```cpp
8+
namespace std::execution {
9+
template<class Sndr, size_t I = 0>
10+
using child-type = decltype(declval<Sndr>().template get<I+2>()); // exposition only
11+
}
12+
```
13+
* template get[link product-type.md]
14+
15+
## 概要
16+
[Senderアルゴリズム型](basic-sender.md)`Sndr`の子Sender型を取得する説明専用のエイリアステンプレート。
17+
18+
19+
## バージョン
20+
### 言語
21+
- C++26
22+
23+
## 関連項目
24+
- [`execution::schedule_from`](schedule_from.md.nolink)
25+
- [`execution::into_variant`](into_variant.md)
26+
27+
28+
## 参照
29+
- [P2300R10 `std::execution`](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2300r10.html)
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
# into_variant
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 into_variant_t { unspecified };
10+
inline constexpr into_variant_t into_variant{};
11+
}
12+
```
13+
* unspecified[italic]
14+
15+
## 概要
16+
`into_variant`は、複数の[値完了シグネチャ](set_value.md)を持つ入力[Sender](sender.md)から複数[`tuple`](/reference/tuple/tuple.md)型からなる[`variant`](/reference/variant/variant.md)型の[値完了シグネチャへと変換](value_types_of_t.md)するSenderアダプタである。
17+
18+
`into_variant`はパイプライン記法をサポートする。
19+
20+
21+
## 効果
22+
説明用の式`sndr`に対して`decltype((sndr))`が[`sender`](sender.md)を満たさないとき、呼び出し式`into_variant(sndr)`は不適格となる。
23+
24+
そうでなければ、呼び出し式`into_variant(sndr)`は`sndr`が1回だけ評価されることを除いて、下記と等価。
25+
26+
```cpp
27+
transform_sender(get-domain-early(sndr), make-sender(into_variant, {}, 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アルゴリズムタグ `into_variant`
35+
Senderアルゴリズム動作説明用のクラステンプレート[`impls-for`](impls-for.md)に対して、下記の特殊化が定義される。
36+
37+
```cpp
38+
namespace std::execution {
39+
template<>
40+
struct impls-for<into_variant_t> : 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+
* see below[italic]
49+
50+
`impls-for<into_variant_t>::get-state`メンバは、下記ラムダ式と等価な関数呼び出し可能なオブジェクトで初期化される。
51+
52+
- 子[Sender](sender.md)の[値完了シグニチャを集約](value_types_of_t.md)した[`variant`](/reference/variant/variant.md)`<`[`tuple`](/reference/variant/variant.md)`<...>, ...>`型をデフォルト構築して返す。
53+
54+
```cpp
55+
[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) noexcept
56+
-> type_identity<value_types_of_t<child-type<Sndr>, env_of_t<Rcvr>>> {
57+
return {};
58+
}
59+
```
60+
* type_identity[link /reference/type_traits/type_identity.md]
61+
* value_types_of_t[link value_types_of_t.md]
62+
* child-type[link child-type.md]
63+
* env_of_t[link env_of_t.md]
64+
65+
`impls-for<into_variant_t>::complete`メンバは、下記ラムダ式と等価な関数呼び出し可能なオブジェクトで初期化される。
66+
67+
- [値完了](set_value.md)の場合、引数パック`args...`から[`variant`](/reference/variant/variant.md)型の送信値を構築して接続先[Receiver](receiver.md)[値完了関数](set_value.md)を呼び出す。
68+
- [エラー完了](set_error.md)または[停止完了](set_stopped.md)の場合、接続先[Receiver](receiver.md)の同種完了関数に全引数を転送する。
69+
70+
```cpp
71+
[]<class State, class Rcvr, class Tag, class... Args>(
72+
auto, State, Rcvr& rcvr, Tag, Args&&... args) noexcept -> void {
73+
if constexpr (same_as<Tag, set_value_t>) {
74+
using variant_type = typename State::type;
75+
TRY-SET-VALUE(rcvr, variant_type(decayed-tuple<Args...>{std::forward<Args>(args)...}));
76+
} else {
77+
Tag()(std::move(rcvr), std::forward<Args>(args)...);
78+
}
79+
}
80+
```
81+
* set_value[link set_value.md]
82+
* decayed-tuple[link decayed-tuple.md]
83+
* std::move[link /reference/utility/move.md]
84+
85+
86+
## カスタマイゼーションポイント
87+
[Sender](sender.md)`sndr`に[関連付けられた実行ドメイン](get-domain-early.md)`dom`に対して、[`execution::transform_sender`](transform_sender.md)経由でSender変換が行われる。
88+
[デフォルト実行ドメイン](../execution/default_domain.md)では無変換。
89+
90+
91+
## 例
92+
```cpp example
93+
#include <string>
94+
#include <tuple>
95+
#include <print>
96+
#include <variant>
97+
#include <stdexec/execution.hpp>
98+
namespace ex = stdexec;
99+
100+
struct FizzBuzzSender {
101+
using sender_concept = ex::sender_t;
102+
using completion_signatures = ex::completion_signatures<
103+
ex::set_value_t(int),
104+
ex::set_value_t(std::string)
105+
>;
106+
107+
template <typename Rcvr>
108+
struct state {
109+
using operation_state_concept = ex::operation_state_t;
110+
111+
state(Rcvr rcvr, int val)
112+
: rcvr_{std::move(rcvr)}, val_{val} {}
113+
114+
void start() noexcept {
115+
if (val_ % 15 == 0) {
116+
ex::set_value(std::move(rcvr_), "FizzBuzz");
117+
} else if (val_ % 3 == 0) {
118+
ex::set_value(std::move(rcvr_), "Fizz");
119+
} else if (val_ % 5 == 0) {
120+
ex::set_value(std::move(rcvr_), "Buzz");
121+
} else {
122+
ex::set_value(std::move(rcvr_), val_);
123+
}
124+
}
125+
126+
Rcvr rcvr_;
127+
int val_;
128+
};
129+
130+
template <typename Rcvr>
131+
auto connect(Rcvr rcvr) noexcept {
132+
return state{std::move(rcvr), val_};
133+
}
134+
135+
int val_;
136+
};
137+
138+
template<typename... Ts>
139+
struct overload : Ts... { using Ts::operator()...; };
140+
141+
int main()
142+
{
143+
int val = 15;
144+
ex::sender auto sndr = ex::into_variant(FizzBuzzSender{val});
145+
auto [result] = std::this_thread::sync_wait(sndr).value();
146+
147+
std::visit(overload{
148+
[](std::tuple<int> n) {
149+
std::println("(int) {}", get<0>(n));
150+
},
151+
[](std::tuple<std::string> s) {
152+
std::println("(str) {}", get<0>(s));
153+
}
154+
}, result);
155+
}
156+
```
157+
* ex::into_variant[color ff0000]
158+
* ex::sender_t[link sender.md]
159+
* ex::sender[link sender.md]
160+
* ex::completion_signatures[link completion_signatures.md]
161+
* ex::set_value_t[link set_value.md]
162+
* ex::set_value[link set_value.md]
163+
* ex::operation_state[link operation_state.md]
164+
* std::this_thread::sync_wait[link ../this_thread/sync_wait.md]
165+
* value()[link /reference/optional/optional/value.md]
166+
* std::move[link /reference/utility/move.md]
167+
* std::visit[link /reference/variant/visit.md]
168+
* get<0>[link /reference/tuple/tuple/get.md]
169+
170+
### 出力
171+
```
172+
(str) FizzBuzz
173+
```
174+
175+
176+
## バージョン
177+
### 言語
178+
- C++26
179+
180+
### 処理系
181+
- [Clang](/implementation.md#clang): ??
182+
- [GCC](/implementation.md#gcc): ??
183+
- [ICC](/implementation.md#icc): ??
184+
- [Visual C++](/implementation.md#visual_cpp): ??
185+
186+
187+
## 関連項目
188+
- [`execution::when_all_with_variant`](when_all_with_variant.md.nolink)
189+
- [`this_thread::sync_wait_with_variant`](../this_thread/sync_wait_with_variant.md)
190+
191+
192+
## 参照
193+
- [P2300R10 `std::execution`](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2300r10.html)

reference/execution/this_thread/sync_wait_with_variant.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ namespace std::this_thread {
2323
2424
2525
## 効果
26-
説明用の`sndr`を`decltype(`[`into_variant`](into_variant.md.nolink)`(sndr))`が`Sndr`型となる式とする。
26+
説明用の`sndr`を`decltype(`[`into_variant`](../execution/into_variant.md)`(sndr))`が`Sndr`型となる式とする。
2727
2828
[`sender_in`](../execution/sender_in.md)`<Sndr,` [`sync-wait-env`](sync-wait-env.md)`> == false`のとき、呼び出し式`this_thread::sync_wait_with_variant(sndr)`は不適格となる。
2929
@@ -55,7 +55,7 @@ namespace std::this_thread {
5555
5656
5757
### Senderアルゴリズムタグ `sync_wait_with_variant`
58-
説明用の`sndr`を`decltype(`[`into_variant`](into_variant.md.nolink)`(sndr))`が`Sndr`型となる式とする。
58+
説明用の`sndr`を`decltype(`[`into_variant`](../execution/into_variant.md)`(sndr))`が`Sndr`型となる式とする。
5959
6060
[`callable`](/reference/functional/callable.md.nolink)`<`[`sync_wait_t`](sync_wait.md)`, Sndr> == false`のとき、式`sync_wait_with_variant.apply_sender(sndr)`は不適格となる。
6161
@@ -69,7 +69,7 @@ if (auto opt_value = sync_wait(into_variant(sndr))) {
6969
return result_type(nullopt);
7070
```
7171
* sync_wait[link sync_wait.md]
72-
* into_variant[link into_variant.md.nolink]
72+
* into_variant[link ../execution/into_variant.md]
7373
* std::move[link /reference/utility/move.md]
7474
* get<0>[link /reference/tuple/tuple/get.md]
7575
* nullopt[link /reference/optional/nullopt_t.md]

0 commit comments

Comments
 (0)