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

履歴 編集

customization point object
<execution>

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

namespace std::execution {
  struct connect_t;
  inline constexpr connect_t connect{};
}

概要

connectは、SenderReceiverを接続した結果Operation Stateを返すカスタマイゼーションポイントオブジェクトである。

呼び出し式connect(sndr, rcvr)は、下記の動作となる。

  • transform_senderによりsndrから新しいSendernew_sndrへ変換する。(多くのケースで無変換)
  • 呼び出し式が適格であるならば、new_sndr.connect(rcvr)を返す。
  • そうでなければ、new_sndrコルーチンのAwaitable型とみなしてrcvrと接続した結果を返す。

効果

説明用の型Sndrdecltype((sndr))、型Rcvrdecltype((rcvr))とし、式new_sndrを次の通りとする。 このときsender<Sndr> && receiver<Rcvr> == trueであること。

transform_sender(decltype(get-domain-late(sndr, get_env(rcvr))){}, sndr, get_env(rcvr))

connect(sndr, rcvr)は下記と等価であり、operation_stateを満たす型の値となる。

  • 適格であるならば、式new_sndr.connect(rcvr)
  • そうでなければ、式connect-awaitable(new_sndr, rcvr)

Awaitable接続用へルパ

説明用のクラスconnect-awaitable-promise, operation-state-taskをそれぞれ下記の通り定義する。

DSdecay_t<decltype((new_sndr))>、型DRdecay_t<Rcvr>とする。

namespace std::execution {
  struct connect-awaitable-promise : with-await-transform<connect-awaitable-promise> {
    connect-awaitable-promise(DS&, DR& rcvr) noexcept : rcvr(rcvr) {}

    suspend_always initial_suspend() noexcept { return {}; }
    [[noreturn]] suspend_always final_suspend() noexcept { terminate(); }
    [[noreturn]] void unhandled_exception() noexcept { terminate(); }
    [[noreturn]] void return_void() noexcept { terminate(); }

    coroutine_handle<> unhandled_stopped() noexcept {
      set_stopped(std::move(rcvr));
      return noop_coroutine();
    }

    operation-state-task get_return_object() noexcept {
      return operation-state-task{
        coroutine_handle<connect-awaitable-promise>::from_promise(*this)};
    }

    env_of_t<DR> get_env() const noexcept {
      return execution::get_env(rcvr);
    }

  private:
    DR& rcvr;  // exposition only
  };
}

namespace std::execution {
  struct operation-state-task {  // exposition only
    using operation_state_concept = operation_state_t;
    using promise_type = connect-awaitable-promise;

    explicit operation-state-task(coroutine_handle<> h) noexcept : coro(h) {}
    operation-state-task(operation-state-task&&) = delete;
    ~operation-state-task() { coro.destroy(); }

    void start() & noexcept {
      coro.resume();
    }

  private:
    coroutine_handle<> coro;  // exposition only
  };
}

C型のcコルーチンPromise型の左辺値pに対して、await-result-type<C, Promise>decltype(GET-AWAITER(c, p).await_resume())型とする。 型Vawait-result-type<DS, connect-awaitable-promise>とする。

完了シグネチャ集合型Sigsを下記の通り定義する。

説明用の関数テンプレートsuspend-completeとコルーチンconnect-awaitableを下記の通り定義する。

namespace std::execution {
  template<class Fun, class... Ts>
  auto suspend-complete(Fun fun, Ts&&... as) noexcept {  // exposition only
    auto fn = [&, fun]() noexcept { fun(std::forward<Ts>(as)...); };

    struct awaiter {
      decltype(fn) fn;  // exposition only

      static constexpr bool await_ready() noexcept { return false; }
      void await_suspend(coroutine_handle<>) noexcept { fn(); }
      [[noreturn]] void await_resume() noexcept { unreachable(); }
    };
    return awaiter{fn};
  }

  operation-state-task connect-awaitable(DS sndr, DR rcvr) requires receiver_of<DR, Sigs> {
    exception_ptr ep;
    try {
      if constexpr (same_as<V, void>) {
        co_await std::move(sndr);
        co_await suspend-complete(set_value, std::move(rcvr));
      } else {
        co_await suspend-complete(set_value, std::move(rcvr), co_await std::move(sndr));
      }
    } catch(...) {
      ep = current_exception();
    }
    co_await suspend-complete(set_error, std::move(rcvr), std::move(ep));
  }
}

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

Sendersndr変換後new_sndrに対して、式new_sndr.connect(rcvr)が呼び出される。

備考

connectSender内部実装から呼び出される想定であり、実行制御ライブラリ利用者が直接利用する必要はない。

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

struct ValueReceiver {
  using receiver_concept = ex::receiver_t;

  void set_value(int v) && noexcept
  {
    std::println("{}", v);
  }
};

int main()
{
  // 値42を送信するSender
  ex::sender auto sndr = ex::just(42);
  // int値を受信して表示するReceiver
  ValueReceiver rcvr;

  // SenderとReceiverを接続
  ex::operation_state auto op = ex::connect(sndr, rcvr);
  // Operation Stateを開始
  ex::start(op);
}

出力

42

バージョン

言語

  • C++26

処理系

関連項目

参照