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)はsndrが1回だけ評価されることを除いて、下記と等価。
transform_sender(get-domain-early(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();
}
};
}
unspecified-exceptionはexceptionから派生した型となる。
説明用の式sndrとenvに対して、型Sndrをdecltype((sndr))、型Envをdecltype((env))とする。sender-for<Sndr, stopped_as_optional_t> == falseのとき、式stopped_as_optional.transform_sender(sndr, env)は不適格となる。
そうではなく、sender_in<child-type<Sndr>, FWD-ENV-T(Env)> == falseのとき、式stopped_as_optional.transform_sender(sndr, env)はnot-a-sender()と等価。
そうでなければ、式stopped_as_optional.transform_sender(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>()); });
カスタマイゼーションポイント
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 Self>
static consteval auto get_completion_signatures()
{
return completion_signatures{};
}
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
処理系
- Clang: ??
- GCC: ??
- ICC: ??
- Visual C++: ??