最終更新日時: 2026年07月22日 16時08分23秒 (JST)
rotarymars が更新

履歴 編集

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`に対して、型`Sndr`を`decltype((sndr))`とする。呼び出し式`stopped_as_optional(sndr)`は下記と等価。

    make-sender(stopped_as_optional, {}, sndr)

### Senderアルゴリズムタグ `stopped_as_optional`

Senderアルゴリズム動作説明用のクラステンプレート`impls-for`に対して、下記の特殊化が定義される。

    namespace std::execution {
      template<>
      struct impls-for<stopped_as_optional_t> : default-impls {
        template<class Sndr, class... Env>
        static consteval void check-types() {
          default-impls::check-types<Sndr, Env...>();
          if constexpr (!requires {
            requires (!same_as<void, single-sender-value-type<child-type<Sndr>, FWD-ENV-T(Env)...>>); })
            throw unspecified-exception();
          }
      };
    }

説明用の式`sndr`と`env`に対して、型`Sndr`を`decltype((sndr))`、型`Env`を`decltype((env))`とする。`sender-for<Sndr, stopped_as_optional_t> == false`のとき、式`stopped_as_optional.transform_sender(set_value, sndr, env)`は不適格となる。

そうではなく、`sender_in<child-type<Sndr>, FWD-ENV-T(Env)> == false`のとき、式`stopped_as_optional.transform_sender(set_value, sndr, env)`は`not-a-sender()`と等価。

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

    auto&& [_, _, child] = sndr;
    using V = single-sender-value-type<child-type<Sndr>, FWD-ENV-T(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>()); });

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

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

## 例

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

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

      using completion_signatures = ex::completion_signatures<
        ex::set_value_t(int),
        ex::set_stopped_t()
      >;
      template <typename Self>
      static consteval auto get_completion_signatures()
      {
        return completion_signatures{};
      }

      template <typename Rcvr>
      struct state {
        using operation_state_concept = ex::operation_state_tag;

        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

### 処理系

- Clang: ??
- GCC: ??
- ICC: ??
- Visual C++: ??

## 関連項目

- `execution::stopped_as_error`

## 参照

- P2300R10 `std::execution`
- P3557R3 High-Quality Sender Diagnostics with Constexpr Exceptions
- LWG 4203. Constraints on `get-state` functions are incorrect
- P3826R5 Fix Sender Algorithm Customization