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

履歴 編集

customization point object
<execution>

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

namespace std::execution {
  struct stopped_as_optional_t { unspecified };
  inline constexpr stopped_as_optional_t stopped_as_optional{};
}

概要

stopped_as_optionalは、入力Sender停止完了を空のoptionalによる値完了にマップするSenderアダプタである。入力Senderの値完了操作もoptionalへと変換される。

stopped_as_optionalパイプ可能Senderアダプタオブジェクトであり、パイプライン記法をサポートする。

効果

説明用の式sndrに対して、型Sndrdecltype((sndr))とする。呼び出し式stopped_as_optional(sndr)sndrが1回だけ評価されることを除いて、下記と等価。

transform_sender(get-domain-early(sndr), make-sender(stopped_as_optional, {}, sndr))

Senderアルゴリズムタグ stopped_as_optional

説明用の式sndrenvに対して、型Sndrdecltype((sndr))、型Envdecltype((env))とする。sender-for<Sndr, stopped_as_optional_t> == false、もしくはsingle-sender-value-type<Sndr, Env>不適格またはvoidのとき、式stopped_as_optional.transform_sender(sndr, env)不適格となる。

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

auto&& [_, _, child] = sndr;
using V = single-sender-value-type<Sndr, Env>;
return let_stopped(
    then(std::forward_like<Sndr>(child),
         []<class... Ts>(Ts&&... ts) noexcept(is_nothrow_constructible_v<V, Ts...>) {
           return optional<V>(in_place, std::forward<Ts>(ts)...);
         }),
    []() noexcept { return just(optional<V>()); });

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

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

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

#include <cassert>
#include <execution>
namespace ex = std::execution;

// MySenderは下記いずれかの完了操作を行う
//   値完了   set_value(int)
//   停止完了 set_stopped()
struct MySender {
  using sender_concept = ex::sender_t;
  using completion_signatures = ex::completion_signatures<
    ex::set_value_t(int),
    ex::set_stopped_t()
  >;

  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 {
      if (0 < val_) {
        ex::set_value(std::move(rcvr_), val_);
      } else {
        ex::set_stopped(std::move(rcvr_));
      }
    }

    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 snd0 = MySender{-1};
    ex::sender auto snd1 = ex::stopped_as_optional(snd0);
    auto [result] = std::this_thread::sync_wait(snd1).value();
    if (result) {
      std::println("(int) {}", *result);
    } else {
      std::println("stopped");
    }
  }

  { // パイプライン記法
    ex::sender auto sndr = MySender{-1} | ex::stopped_as_optional();
    auto [result] = std::this_thread::sync_wait(sndr).value();
    if (result) {
      std::println("(int) {}", *result);
    } else {
      std::println("stopped");
    }
  }
}

出力

stopped
stopped

バージョン

言語

  • C++26

処理系

関連項目

参照