namespace std::execution {
struct connect_t;
inline constexpr connect_t connect{};
}
概要
connect
は、SenderとReceiverを接続した結果Operation Stateを返すカスタマイゼーションポイントオブジェクトである。
呼び出し式connect(sndr, rcvr)
は、下記の動作となる。
transform_sender
によりsndr
から新しいSendernew_sndr
へ変換する。(多くのケースで無変換)- 呼び出し式が適格であるならば、
new_sndr.connect(rcvr)
を返す。 - そうでなければ、
new_sndr
をコルーチンのAwaitable型とみなしてrcvr
と接続した結果を返す。
効果
説明用の型Sndr
をdecltype((sndr))
、型Rcvr
をdecltype((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
をそれぞれ下記の通り定義する。
型DS
をdecay_t<decltype((new_sndr))>
、型DR
をdecay_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())
型とする。
型V
をawait-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)
が呼び出される。
備考
connect
はSender内部実装から呼び出される想定であり、実行制御ライブラリ利用者が直接利用する必要はない。
例
#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
処理系
- Clang: ??
- GCC: ??
- ICC: ??
- Visual C++: ??