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

履歴 編集

customization point object
<execution>

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

namespace std::execution {
  struct when_all_with_variant_t { unspecified };
  inline constexpr when_all_with_variant_t when_all_with_variant{};
}

概要

when_all_with_variantは、複数の入力Senderが全て完了するまで待機するSenderアダプタである。

when_all_with_variantは入力Senderが複数の値完了シグネチャを持つケースに対応する。 全入力Senderの値完了シグネチャが1個だけの場合はwhen_allアルゴリズムを利用する。

  • 入力Sender全てが値完了のとき、全ての値完了結果をvarianttupleに結合して値完了操作を行う。
  • いずれかがエラー完了のとき、同エラー値をもってエラー完了操作を行う。このとき停止要求が作成される。
  • いずれかが停止完了のとき、停止完了操作を行う。このとき停止要求が作成される。

効果

説明用のパックsndrsに対してパックSndrsdecltype((sndrs))...としたとき、型CDcommon_type_t<decltype(get-domain-early(sndrs))...>とする。

下記いずれかがtrueとなるとき、呼び出し式when_all_with_variant(sndrs...)不適格となる。

  • sizeof...(sndrs) == 0、または
  • (sender<Sndrs> && ...) == false、または
  • CD不適格

そうでなければ、呼び出し式when_all_with_variant(sndrs...)は下記と等価。

transform_sender(CD(), make-sender(when_all_with_variant, {}, sndrs...))

Senderアルゴリズムタグ when_all_with_variant

説明用の式sndrenvに対して、sender-for<decltype((sndr)), when_all_with_variant_t> == falseのとき、式when_all_with_variant.transform_sender(sndr, env)不適格となる。

そうでなければ、式when_all_with_variant.transform_sender(sndr, env)は下記と等価。

auto&& [_, _, ...child] = sndr;
return when_all(into_variant(std::forward_like<decltype((sndr))>(child))...);

カスタマイゼーションポイント

Senderアルゴリズム構築時に、全入力Senderに関連付けられた共通の実行ドメインCDに対してexecution::transform_sender経由でSender変換が行われる。 デフォルト実行ドメインでは無変換。

Receiverとの接続(connect)時に、関連付けられた実行ドメインに対してexecution::transform_sender経由でSender変換が行われる。 デフォルト実行ドメインではwhen_all_with_variant.transform_sender(sndr, env)が呼ばれ、前述仕様通りのSenderへと変換される。

#include <print>
#include <string>
#include <execution>
namespace ex = std::execution;

// MySenderは下記いずれかの完了操作を行う
//   値完了     set_value(int), set_value(string)
//   エラー完了 set_error(int)
struct MySender {
  using sender_concept = ex::sender_t;
  using completion_signatures = ex::completion_signatures<
    ex::set_value_t(int),
    ex::set_value_t(std::string),
    ex::set_error_t(int)
  >;

  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;
      switch (val_) {
      case 1:
        ex::set_value(std::move(rcvr_), 100);
        break;
      case 2:
        ex::set_value(std::move(rcvr_), "C++"s);
        break;
      default:
        ex::set_error(std::move(rcvr_), val_);
        break;
      }
    }

    Rcvr rcvr_;
    int val_;
  };

  template <typename Rcvr>
  auto connect(Rcvr rcvr) noexcept {
    return state{std::move(rcvr), val_};
  }

  int val_;
};

int main()
{
  ex::sender auto snd1 = MySender{1};
  ex::sender auto snd2 = MySender{2};
  ex::sender auto sndr = ex::when_all_with_variant(snd1, snd2);

  auto result = std::this_thread::sync_wait(sndr);
  // result := optional<
  //             tuple<
  //               variant<tuple<int>, tuple<string>>,
  //               variant<tuple<int>, tuple<string>>
  //             >
  //           >型

  auto [val1, val2] = result.value();
  // val1,val2 := variant<tuple<int>, tuple<string>>型

  struct DumpVal {
    void operator()(std::tuple<int> n) {
      std::println("(int) {}", get<0>(n));
    }
    void operator()(std::tuple<std::string> s) {
      std::println("(str) {}", get<0>(s));
    }
  };
  std::visit(DumpVal{}, val1);
  std::visit(DumpVal{}, val2);
}

出力

(int) 100
(str) C++

バージョン

言語

  • C++26

処理系

関連項目

参照