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を次の通りとする。
transform_sender(decltype(get-domain-late(sndr, get_env(rcvr))){}, sndr, get_env(rcvr))
式connect(sndr, rcvr)はrcvrが1回だけ評価されることを除いて、下記と等価。式の型はoperation_stateを満たす。
- 適格であるならば、式
new_sndr.connect(rcvr) - そうでなければ、式
connect-awaitable(new_sndr, rcvr)
このとき下記が全てtrueであること。
sender_in<Sndr, env_of_t<Rcvr>>receiver_of<Rcvr, completion_signatures_of_t<Sndr, env_of_t<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())型とし、await-result-type<C>をdecltype(GET-AWAITER(c).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++: ??