最終更新日時(UTC):
が更新

履歴 編集

customization point object
<execution>

std::execution::into_variant(C++26)

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メンバは、下記ラムダ式と等価な関数呼び出し可能なオブジェクトで初期化される。

[]<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メンバは、下記ラムダ式と等価な関数呼び出し可能なオブジェクトで初期化される。

[]<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

処理系

関連項目

参照