namespace std::execution {
struct into_variant_t { unspecified };
inline constexpr into_variant_t into_variant{};
}
概要
into_variant
は、複数の値完了シグネチャを持つ入力Senderから複数tuple
型からなるvariant
型の値完了シグネチャへと変換するSenderアダプタである。
into_variant
はパイプ可能Senderアダプタオブジェクトであり、パイプライン記法をサポートする。
効果
説明用の式sndr
に対してdecltype((sndr))
がsender
を満たさないとき、呼び出し式into_variant(sndr)
は不適格となる。
そうでなければ、呼び出し式into_variant(sndr)
はsndr
が1回だけ評価されることを除いて、下記と等価。
transform_sender(get-domain-early(sndr), make-sender(into_variant, {}, sndr))
Senderアルゴリズムタグ into_variant
Senderアルゴリズム動作説明用のクラステンプレートimpls-for
に対して、下記の特殊化が定義される。
namespace std::execution {
template<>
struct impls-for<into_variant_t> : default-impls {
static constexpr auto get-state = see below;
static constexpr auto complete = see below;
};
}
impls-for<into_variant_t>::get-state
メンバは、下記ラムダ式と等価な関数呼び出し可能なオブジェクトで初期化される。
- 子Senderの値完了シグネチャを集約した
variant<tuple<...>, ...>
型をtype_identity
クラステンプレートのパラメータに格納して返す。
[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) noexcept
-> type_identity<value_types_of_t<child-type<Sndr>, env_of_t<Rcvr>>> {
return {};
}
impls-for<into_variant_t>::complete
メンバは、下記ラムダ式と等価な関数呼び出し可能なオブジェクトで初期化される。
State
として渡される前述get-state
メンバ戻り値型(type_identity
)から、into_varinat
の送信値となるvariant<tuple<...>, ...>
型情報を取り出す。- 値完了の場合、引数パック
args...
から送信値を構築して接続先Receiverの値完了関数を呼び出す。 - エラー完了または停止完了の場合、接続先Receiverの同種完了関数に全引数を転送する。
[]<class State, class Rcvr, class Tag, class... Args>(
auto, State, Rcvr& rcvr, Tag, Args&&... args) noexcept -> void {
if constexpr (same_as<Tag, set_value_t>) {
using variant_type = typename State::type;
TRY-SET-VALUE(rcvr, variant_type(decayed-tuple<Args...>{std::forward<Args>(args)...}));
} else {
Tag()(std::move(rcvr), std::forward<Args>(args)...);
}
}
カスタマイゼーションポイント
Senderアルゴリズム構築時およびReceiver接続時に、関連付けられた実行ドメインに対してexecution::transform_sender
経由でSender変換が行われる。
デフォルト実行ドメインでは無変換。
例
#include <string>
#include <tuple>
#include <print>
#include <variant>
#include <execution>
namespace ex = std::execution;
struct FizzBuzzSender {
using sender_concept = ex::sender_t;
// FizzBuzzSenderは2種類の値完了シグネチャを持つ
using completion_signatures = ex::completion_signatures<
ex::set_value_t(int),
ex::set_value_t(std::string)
>;
// Operation State型
template <typename Rcvr>
struct State {
using operation_state_concept = ex::operation_state_t;
State(Rcvr rcvr, int val)
: rcvr_{std::move(rcvr)}, val_{val} {}
void start() noexcept {
using namespace std::string_literals;
if (val_ % 15 == 0) {
ex::set_value(std::move(rcvr_), "FizzBuzz"s);
} else if (val_ % 3 == 0) {
ex::set_value(std::move(rcvr_), "Fizz"s);
} else if (val_ % 5 == 0) {
ex::set_value(std::move(rcvr_), "Buzz"s);
} else {
ex::set_value(std::move(rcvr_), val_);
}
}
Rcvr rcvr_;
int val_;
};
template <typename Rcvr>
auto connect(Rcvr rcvr) noexcept {
return State{std::move(rcvr), val_};
}
int val_;
};
template<typename... Ts>
struct overload : Ts... { using Ts::operator()...; };
int main()
{
int val = 15;
#if 0
// 関数呼び出し
ex::sender auto snd0 = FizzBuzzSender{val};
ex::sender auto sndr = ex::into_variant(snd0);
#else
// パイプライン記法
ex::sender auto sndr = FizzBuzzSender{val} | ex::into_variant();
#endif
auto [result] = std::this_thread::sync_wait(sndr).value();
// result := variant<tuple<int>, tuple<string>>型
std::visit(overload{
[](std::tuple<int> n) {
std::println("(int) {}", get<0>(n));
},
[](std::tuple<std::string> s) {
std::println("(str) {}", get<0>(s));
}
}, result);
}
出力
(str) FizzBuzz
バージョン
言語
- C++26
処理系
- Clang: ??
- GCC: ??
- ICC: ??
- Visual C++: ??