A sender adaptor is prohibited from causing observable effects,
apart from moving and copying its arguments,
before the returned sender is connected with a receiver using connect,
and start is called on the resulting operation state.
A parent sender ([exec.async.ops]) with a single child sender sndr has
an associated attribute object equal to
FWD-ENV(get_env(sndr)) ([exec.fwd.env]).
When a parent sender is connected to a receiver rcvr,
any receiver used to connect a child sender has
an associated environment equal to FWD-ENV(get_env(rcvr)).
If a sender returned from a sender adaptor specified in [exec.adapt]
is specified to include set_error_t(Err)
among its set of completion signatures
where decay_t<Err> denotes the type exception_ptr,
but the implementation does not potentially evaluate
an error completion operation with an exception_ptr argument,
the implementation is allowed to omit
the exception_ptr error completion signature from the set.
For a pipeable sender adaptor closure object c and
an expression sndr
such that decltype((sndr)) models sender,
the following expressions are equivalent and yield a sender:
c(sndr)
sndr | c
Given an additional pipeable sender adaptor closure object d,
the expression c | d produces
another pipeable sender adaptor closure object e:
e is a perfect forwarding call wrapper ([func.require])
with the following properties:
An object t of type T is
a pipeable sender adaptor closure object
if T models derived_from<sender_adaptor_closure<T>>,
T has no other base classes
of type sender_adaptor_closure<U> for any other type U, and
T does not satisfy sender.
The template parameter D for sender_adaptor_closure can be
an incomplete type.
Before any expression of type cvD appears as
an operand to the | operator,
D shall be complete and
model derived_from<sender_adaptor_closure<D>>.
The behavior of an expression involving an object of type cvD
as an operand to the | operator is undefined
if overload resolution selects a program-defined operator| function.
If a pipeable sender adaptor object adaptor accepts more than one argument,
then let sndr be an expression
such that decltype((sndr)) models sender,
let args... be arguments
such that adaptor(sndr, args...) is a well-formed expression
as specified below, and
let BoundArgs be a pack that denotes decltype(auto(args))....
The expression adaptor(args...) produces
a pipeable sender adaptor closure object f
that is a perfect forwarding call wrapper with the following properties:
Its bound argument entities bound_args consist of
objects of types BoundArgs... direct-non-list-initialized with
std::forward<decltype((args))>(args)..., respectively.
Its call pattern is adaptor(rcvr, bound_args...),
where rcvr is
the argument used in a function call expression of f.
The expression adaptor(args...) is well-formed if and only if
the initializations of the bound argument entities of the result,
as specified above, are all well-formed.
starts_on adapts an input sender into a sender
that will start on an execution agent belonging to
a particular scheduler's associated execution resource.
The name starts_on denotes a customization point object.
For subexpressions sch and sndr,
if decltype(( sch)) does not satisfy scheduler, or
decltype((sndr)) does not satisfy sender,
starts_on(sch, sndr) is ill-formed.
Otherwise,
the expression starts_on(sch, sndr) is expression-equivalent to:
transform_sender(query-or-default(get_domain, sch, default_domain()),
make-sender(starts_on, sch, sndr))
except that sch is evaluated only once.
Let out_sndr and env be subexpressions
such that OutSndr is decltype((out_sndr)).
If sender-for<OutSndr, starts_on_t> is false,
then the expressions starts_on.transform_env(out_sndr, env) and
starts_on.transform_sender(out_sndr, env) are ill-formed; otherwise
Let out_sndr be a subexpression denoting
a sender returned from starts_on(sch, sndr) or one equal to such, and
let OutSndr be the type decltype((out_sndr)).
Let out_rcvr be a subexpression denoting a receiver
that has an environment of type Env
such that sender_in<OutSndr, Env> is true.
Let op be an lvalue referring to the operation state
that results from connecting out_sndr with out_rcvr.
Calling start(op) shall start sndr
on an execution agent of the associated execution resource of sch.
If scheduling onto sch fails,
an error completion on out_rcvr shall be executed
on an unspecified execution agent.
The name continues_on denotes a pipeable sender adaptor object.
For subexpressions sch and sndr,
if decltype((sch)) does not satisfy scheduler, or
decltype((sndr)) does not satisfy sender,
continues_on(sndr, sch) is ill-formed.
Otherwise,
the expression continues_on(sndr, sch) is expression-equivalent to:
transform_sender(get-domain-early(sndr), make-sender(continues_on, sch, sndr))
except that sndr is evaluated only once.
The exposition-only class template impls-for
is specialized for continues_on_t as follows:
namespace std::execution {template<>structimpls-for<continues_on_t>:default-impls{staticconstexprautoget-attrs=[](constauto& data, constauto& child)noexcept->decltype(auto){returnJOIN-ENV(SCHED-ATTRS(data), FWD-ENV(get_env(child)));
};
};
}
Let sndr and env be subexpressions
such that Sndr is decltype((sndr)).
If sender-for<Sndr, continues_on_t> is false,
then
the expression continues_on.transform_sender(sndr, env) is ill-formed;
otherwise, it is equal to:
auto[_, data, child]= sndr;
return schedule_from(std::move(data), std::move(child));
This causes the continues_on(sndr, sch) sender to become
schedule_from(sch, sndr) when it is connected with a receiver
whose execution domain does not customize continues_on.
Let out_sndr be a subexpression denoting
a sender returned from continues_on(sndr, sch) or one equal to such, and
let OutSndr be the type decltype((out_sndr)).
Let out_rcvr be a subexpression denoting a receiver
that has an environment of type Env
such that sender_in<OutSndr, Env> is true.
Let op be an lvalue referring to the operation state
that results from connecting out_sndr with out_rcvr.
Calling start(op) shall
start sndr on the current execution agent and
execute completion operations on out_rcvr
on an execution agent of the execution resource associated with sch.
If scheduling onto sch fails,
an error completion on out_rcvr shall be executed
on an unspecified execution agent.
Otherwise,
the expression schedule_from(sch, sndr) is expression-equivalent to:
transform_sender(query-or-default(get_domain, sch, default_domain()),
make-sender(schedule_from, sch, sndr))
except that sch is evaluated only once.
The exposition-only class template impls-for ([exec.snd.general])
is specialized for schedule_from_t as follows:
namespace std::execution {template<>structimpls-for<schedule_from_t>:default-impls{staticconstexprautoget-attrs=see below;
staticconstexprautoget-state=see below;
staticconstexprautocomplete=see below;
};
}
The member impls-for<schedule_from_t>::get-attrs
is initialized with a callable object equivalent to the following lambda:
[](constauto& data, constauto& child)noexcept->decltype(auto){returnJOIN-ENV(SCHED-ATTRS(data), FWD-ENV(get_env(child)));
}
The member impls-for<schedule_from_t>::get-state
is initialized with a callable object equivalent to the following lambda:
[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr)noexcept(see below)requiressender_in<child-type<Sndr>, env_of_t<Rcvr>>{auto&[_, sch, child]= sndr;
using sched_t =decltype(auto(sch));
using variant_t =see below;
using receiver_t =see below;
using operation_t = connect_result_t<schedule_result_t<sched_t>, receiver_t>;
constexprbool nothrow =noexcept(connect(schedule(sch), receiver_t{nullptr}));
structstate-type{
Rcvr&rcvr; // exposition only
variant_t async-result; // exposition only
operation_t op-state; // exposition onlyexplicitstate-type(sched_t sch, Rcvr& rcvr)noexcept(nothrow):rcvr(rcvr), op-state(connect(schedule(sch), receiver_t{this})){}};
returnstate-type{sch, rcvr};
}
The expression in the noexcept clause of the lambda is true
if the construction of the returned state-type object
is not potentially throwing;
otherwise, false.
Let out_sndr be a subexpression denoting
a sender returned from schedule_from(sch, sndr) or one equal to such,
and let OutSndr be the type decltype((out_sndr)).
Let out_rcvr be a subexpression denoting a receiver
that has an environment of type Env
such that sender_in<OutSndr, Env> is true.
Let op be an lvalue referring to the operation state
that results from connecting out_sndr with out_rcvr.
Calling start(op) shall
start sndr on the current execution agent and
execute completion operations on out_rcvr
on an execution agent of the execution resource associated with sch.
If scheduling onto sch fails,
an error completion on out_rcvr shall be executed
on an unspecified execution agent.
on(sch, sndr),
which starts a sender sndr on an execution agent
belonging to a scheduler sch's associated execution resource and
that, upon sndr's completion,
transfers execution back to the execution resource
on which the on sender was started.
on(sndr, sch, closure),
which upon completion of a sender sndr,
transfers execution to an execution agent
belonging to a scheduler sch's associated execution resource,
then executes a sender adaptor closure closure
with the async results of the sender, and
that then transfers execution back to the execution resource
on which sndr completed.
Otherwise, if decltype((sndr)) satisfies sender,
the expression on(sch, sndr) is expression-equivalent to:
transform_sender(query-or-default(get_domain, sch, default_domain()),
make-sender(on, sch, sndr))
except that sch is evaluated only once.
closure is not a pipeable sender adaptor closure object ([exec.adapt.obj]),
the expression on(sndr, sch, closure) is ill-formed;
otherwise, it is expression-equivalent to:
transform_sender(get-domain-early(sndr),
make-sender(on, product-type{sch, closure}, sndr))
except that sndr is evaluated only once.
Otherwise:
Let not-a-scheduler be an unspecified empty class type, and
let not-a-sender be the exposition-only type:
structnot-a-sender{using sender_concept = sender_t;
auto get_completion_signatures(auto&&)const{returnsee below;
}};
where the member function get_completion_signatures returns
an object of a type that is not
a specialization of the completion_signatures class template.
Recommended practice: Implementations should use
the return type of not-a-sender::get_completion_signatures
to inform users that their usage of on is incorrect
because there is no available scheduler onto which to restore execution.
Let out_sndr be a subexpression denoting
a sender returned from on(sndr, sch, closure) or one equal to such, and
let OutSndr be the type decltype((out_sndr)).
Let out_rcvr be a subexpression denoting a receiver
that has an environment of type Env
such that sender_in<OutSndr, Env> is true.
Let op be an lvalue referring to the operation state
that results from connecting out_sndr with out_rcvr.
forward sndr's async result as if by
connecting and starting a sender closure(S),
where S is a sender
that completes synchronously with sndr's async result; and
upon completion of the operation started in the previous step,
transfer execution back to the execution resource
associated with the scheduler remembered in step 1 and
forward the operation's async result to out_rcvr.
If any scheduling operation fails,
an error completion on out_rcvr shall be executed on
an unspecified execution agent.
then attaches an invocable as a continuation
for an input sender's value completion operation.
upon_error and upon_stopped do the same
for the error and stopped completion operations, respectively,
sending the result of the invocable as a value completion.
The names then, upon_error, and upon_stopped
denote pipeable sender adaptor objects.
Let the expression then-cpo be one of
then, upon_error, or upon_stopped.
For subexpressions sndr and f,
if decltype((sndr)) does not satisfy sender, or
decltype((f)) does not satisfy movable-value,
then-cpo(sndr, f)is ill-formed.
Otherwise,
the expression then-cpo(sndr, f) is expression-equivalent to:
transform_sender(get-domain-early(sndr), make-sender(then-cpo, f, sndr))
except that sndr is evaluated only once.
invokes f or a copy of such
with the value, error, or stopped result datums of sndr
for then, upon_error, and upon_stopped, respectively,
using the result value of f as out_sndr's value completion, and
let_value, let_error, and let_stopped transform
a sender's value, error, and stopped completions, respectively,
into a new child asynchronous operation
by passing the sender's result datums to a user-specified callable,
which returns a new sender that is connected and started.
Otherwise,
the expression let-cpo(sndr, f) is expression-equivalent to:
transform_sender(get-domain-early(sndr), make-sender(let-cpo, f, sndr))
except that sndr is evaluated only once.
impls-for<decayed-typeof<let-cpo>>::get-state
is initialized with a callable object equivalent to the following:
[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr)requiressee below{auto&[_, fn, child]= sndr;
using fn_t = decay_t<decltype(fn)>;
using env_t =decltype(let-env(child));
using args_variant_t =see below;
using ops2_variant_t =see below;
structstate-type{
fn_t fn; // exposition only
env_t env; // exposition only
args_variant_t args; // exposition only
ops2_variant_t ops2; // exposition only};
returnstate-type{std::forward_like<Sndr>(fn), let-env(child), {}, {}};
}
Given a type Tag and a pack Args,
let as-sndr2 be an alias template
such that as-sndr2<Tag(Args...)> denotes
the type call-result-t<Fn, decay_t<Args>&...>.
Then ops2_variant_t denotes
the type
variant<monostate, connect_result_t<as-sndr2<LetSigs>, receiver2<Rcvr, Env>>...>
except with duplicate types removed.
The exposition-only function template let-bind
has effects equivalent to:
using args_t =decayed-tuple<Args...>;
auto mkop2 =[&]{return connect(
apply(std::move(state.fn),
state.args.template emplace<args_t>(std::forward<Args>(args)...)),
receiver2{rcvr, std::move(state.env)});
};
start(state.ops2.template emplace<decltype(mkop2())>(emplace-from{mkop2}));
Let the subexpression out_sndr denote
the result of the invocation let-cpo(sndr, f) or
an object equal to such, and
let the subexpression rcvr denote a receiver
such that the expression connect(out_sndr, rcvr) is well-formed.
The expression connect(out_sndr, rcvr) has undefined behavior
unless it creates an asynchronous operation ([exec.async.ops]) that,
when started:
The exposition-only class template impls-for ([exec.snd.general])
is specialized for bulk_t as follows:
namespace std::execution {template<>structimpls-for<bulk_t>:default-impls{staticconstexprautocomplete=see below;
};
}
The member impls-for<bulk_t>::complete
is initialized with a callable object equivalent to the following lambda:
[]<class Index, class State, class Rcvr, class Tag, class... Args>(Index, State& state, Rcvr& rcvr, Tag, Args&&... args)noexcept->voidrequiressee below{ifconstexpr(same_as<Tag, set_value_t>){auto&[shape, f]= state;
constexprbool nothrow =noexcept(f(auto(shape), args...));
TRY-EVAL(rcvr, [&]()noexcept(nothrow){for(decltype(auto(shape)) i =0; i < shape; ++i){
f(auto(i), args...);
}
Tag()(std::move(rcvr), std::forward<Args>(args)...);
}());
}else{
Tag()(std::move(rcvr), std::forward<Args>(args)...);
}}
The expression in the requires-clause of the lambda above
is true if and only
if Tag denotes a type other than set_value_t or
if the expression f(auto(shape), args...) is well-formed.
Let the subexpression out_sndr denote
the result of the invocation bulk(sndr, shape, f) or
an object equal to such, and
let the subexpression rcvr denote a receiver
such that the expression connect(out_sndr, rcvr) is well-formed.
The expression connect(out_sndr, rcvr) has undefined behavior
unless it creates an asynchronous operation ([exec.async.ops]) that,
when started,
on a value completion operation,
invokes f(i, args...)
for every i of type Shape from 0 to shape,
where args is a pack of lvalue subexpressions
referring to the value completion result datums of the input sender, and
Let split-env be the type of an environment
such that, given an instance env,
the expression get_stop_token(env) is well-formed and
has type inplace_stop_token.
Otherwise, the expression split(sndr) is expression-equivalent to:
transform_sender(get-domain-early(sndr), make-sender(split, {}, sndr))
except that sndr is evaluated only once.
Let Sigs be a pack of the arguments
to the completion_signatures specialization
named by completion_signatures_of_t<Sndr>.
For type Tag and pack Args,
let as-tuple be an alias template
such that as-tuple<Tag(Args...)> denotes
the type decayed-tuple<Tag, Args...>.
Then variant-type denotes the type
variant<tuple<set_stopped_t>, tuple<set_error_t, exception_ptr>, as-tuple<Sigs>...>
but with duplicate types removed.
Synchronization: If an evaluation of dec-ref() does not
decrement the ref_count to 0 then
synchronizes with the evaluation of dec-ref()
that decrements ref_count to 0.
Let split-impl-tag be an empty exposition-only class type.
Given an expression sndr,
the expression split.transform_sender(sndr) is equivalent to:
auto&&[tag, _, child]= sndr;
auto* sh_state =newshared-state{std::forward_like<decltype((sndr))>(child)};
returnmake-sender(split-impl-tag(), shared-wrapper{sh_state, tag});
where shared-wrapper is an exposition-only class
that manages the reference count of the shared-state object
pointed to by sh_state.
shared-wrapper models copyable
with move operations nulling out the moved-from object,
copy operations incrementing the reference count
by calling sh_state->inc-ref(), and
assignment operations performing a copy-and-swap operation.
The destructor has no effect if sh_state is null;
otherwise, it decrements the reference count
by evaluating sh_state->dec-ref().
The exposition-only class template impls-for ([exec.snd.general])
is specialized for split-impl-tag as follows:
namespace std::execution {template<>structimpls-for<split-impl-tag>:default-impls{staticconstexprautoget-state=see below;
staticconstexprautostart=see below;
};
}
The member
impls-for<split-impl-tag>::get-state
is initialized with a callable object equivalent to
the following lambda expression:
[]<class Sndr>(Sndr&& sndr, auto& rcvr)noexcept{returnlocal-state{std::forward<Sndr>(sndr), rcvr};
}
The member
impls-for<split-impl-tag>::start
is initialized with a callable object
that has a function call operator equivalent to the following:
template<class Sndr, class Rcvr>voidoperator()(local-state<Sndr, Rcvr>& state, Rcvr& rcvr)constnoexcept;
Effects: If state.sh_state->completed is true,
evaluates state.notify() and returns.
when_all and when_all_with_variant
both adapt multiple input senders into a sender
that completes when all input senders have completed.
when_all only accepts senders
with a single value completion signature and
on success concatenates all the input senders' value result datums
into its own value completion operation.
when_all_with_variant(sndrs...) is semantically equivalent to
when_all(into_variant(sndrs)...),
where sndrs is a pack of subexpressions
whose types model sender.
The names when_all and when_all_with_variant denote
customization point objects.
Let sndrs be a pack of subexpressions,
let Sndrs be a pack of the types decltype((sndrs))..., and
let CD be
the type common_type_t<decltype(get-domain-early(sndrs))...>.
The expressions when_all(sndrs...) and
when_all_with_variant(sndrs...) are ill-formed
if any of the following is true:
The member impls-for<when_all_t>::get-attrs
is initialized with a callable object
equivalent to the following lambda expression:
[](auto&&, auto&&... child)noexcept{ifconstexpr(same_as<CD, default_domain>){return empty_env();
}else{returnMAKE-ENV(get_domain, CD());
}}
The member impls-for<when_all_t>::get-env
is initialized with a callable object
equivalent to the following lambda expression:
[]<class State, class Rcvr>(auto&&, State& state, const Receiver& rcvr)noexcept{returnJOIN-ENV(MAKE-ENV(get_stop_token, state.stop_src.get_token()), get_env(rcvr));
}
The member impls-for<when_all_t>::get-state
is initialized with a callable object
equivalent to the following lambda expression:
[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr)noexcept(e)->decltype(e){returne;
}
where e is the expression
std::forward<Sndr>(sndr).apply(make-state<Rcvr>())
and where make-state is the following exposition-only class template:
template<class Sndr, class Env>conceptmax-1-sender-in=sender_in<Sndr, Env>&&// exposition only(tuple_size_v<value_types_of_t<Sndr, Env, tuple, tuple>><=1);
enumclassdisposition{started, error, stopped}; // exposition onlytemplate<class Rcvr>structmake-state{template<max-1-sender-in<env_of_t<Rcvr>>... Sndrs>autooperator()(auto, auto, Sndrs&&... sndrs)const{using values_tuple =see below;
using errors_variant =see below;
using stop_callback = stop_callback_for_t<stop_token_of_t<env_of_t<Rcvr>>, on-stop-request>;
structstate-type{voidarrive(Rcvr& rcvr)noexcept{// exposition onlyif(0==--count){complete(rcvr);
}}voidcomplete(Rcvr& rcvr)noexcept; // exposition only
atomic<size_t>count{sizeof...(sndrs)}; // exposition only
inplace_stop_source stop_src{}; // exposition only
atomic<disposition> disp{disposition::started}; // exposition only
errors_variant errors{}; // exposition only
values_tuple values{}; // exposition only
optional<stop_callback>on_stop{nullopt}; // exposition only};
returnstate-type{};
}};
Let copy-fail be exception_ptr
if decay-copying any of the child senders' result datums can potentially throw;
otherwise, none-such,
where none-such is an unspecified empty class type.
The alias values_tuple denotes the type
tuple<value_types_of_t<Sndrs, env_of_t<Rcvr>, decayed-tuple, optional>...>
if that type is well-formed; otherwise, tuple<>.
The alias errors_variant denotes
the type variant<none-such, copy-fail, Es...>
with duplicate types removed,
where Es is the pack of the decayed types
of all the child senders' possible error result datums.
If disp is equal to disposition::started,
evaluates:
auto tie =[]<class... T>(tuple<T...>& t)noexcept{return tuple<T&...>(t); };
auto set =[&](auto&... t)noexcept{ set_value(std::move(rcvr), std::move(t)...); };
on_stop.reset();
apply([&](auto&... opts)noexcept{
apply(set, tuple_cat(tie(*opts)...));
},
values);
The member impls-for<when_all_t>::start
is initialized with a callable object
equivalent to the following lambda expression:
[]<class State, class Rcvr, class... Ops>(
State& state, Rcvr& rcvr, Ops&... ops)noexcept->void{
state.on_stop.emplace(
get_stop_token(get_env(rcvr)),
on-stop-request{state.stop_src});
if(state.stop_src.stop_requested()){
state.on_stop.reset();
set_stopped(std::move(rcvr));
}else{(start(ops), ...);
}}
The member impls-for<when_all_t>::complete
is initialized with a callable object
equivalent to the following lambda expression:
[]<class Index, class State, class Rcvr, class Set, class... Args>(thisauto& complete, Index, State& state, Rcvr& rcvr, Set, Args&&... args)noexcept->void{ifconstexpr(same_as<Set, set_error_t>){if(disposition::error!= state.disp.exchange(disposition::error)){
state.stop_src.request_stop();
TRY-EMPLACE-ERROR(state.errors, std::forward<Args>(args)...);
}}elseifconstexpr(same_as<Set, set_stopped_t>){auto expected =disposition::started;
if(state.disp.compare_exchange_strong(expected, disposition::stopped)){
state.stop_src.request_stop();
}}elseifconstexpr(!same_as<decltype(State::values), tuple<>>){if(state.disp ==disposition::started){auto& opt = get<Index::value>(state.values);
TRY-EMPLACE-VALUE(complete, opt, std::forward<Args>(args)...);
}}
state.arrive(rcvr);
}
where TRY-EMPLACE-ERROR(v, e),
for subexpressions v and e, is equivalent to:
try{
v.template emplace<decltype(auto(e))>(e);
}catch(...){
v.template emplace<exception_ptr>(current_exception());
}
if the expression decltype(auto(e))(e) is potentially throwing;
otherwise, v.template emplace<decltype(auto(e))>(e);
and where TRY-EMPLACE-VALUE(c, o, as...),
for subexpressions c, o, and pack of subexpressions as,
is equivalent to:
try{
o.emplace(as...);
}catch(...){
c(Index(), state, rcvr, set_error, current_exception());
return;
}
if the expression decayed-tuple<decltype(as)...>{as...}
is potentially throwing;
otherwise, o.emplace(as...).
Given subexpressions sndr and env,
if
sender-for<decltype((sndr)), when_all_with_variant_t>
is false,
then the expression when_all_with_variant.transform_sender(sndr, env)
is ill-formed;
otherwise, it is equivalent to:
auto&&[_, _, ...child]= sndr;
return when_all(into_variant(std::forward_like<decltype((sndr))>(child))...);
This causes the when_all_with_variant(sndrs...) sender
to become when_all(into_variant(sndrs)...)
when it is connected with a receiver
whose execution domain does not customize when_all_with_variant.
into_variant adapts a sender with multiple value completion signatures
into a sender with just one value completion signature
consisting of a variant of tuples.
Otherwise, the expression into_variant(sndr)
is expression-equivalent to:
transform_sender(get-domain-early(sndr), make-sender(into_variant, {}, sndr))
except that sndr is only evaluated once.
The exposition-only class template impls-for ([exec.snd.general])
is specialized for into_variant as follows:
namespace std::execution {template<>structimpls-for<into_variant_t>:default-impls{staticconstexprautoget-state=see below;
staticconstexprautocomplete=see below;
};
}
The member impls-for<into_variant_t>::get-state
is initialized with a callable object equivalent to the following lambda:
[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr)noexcept-> type_identity<value_types_of_t<child-type<Sndr>, env_of_t<Rcvr>>>{return{};
}
The member impls-for<into_variant_t>::complete
is initialized with a callable object equivalent to the following lambda:
[]<class State, class Rcvr, class Tag, class... Args>(auto, State, Rcvr& rcvr, Tag, Args&&... args)noexcept->void{ifconstexpr(same_as<Tag, set_value_t>){using variant_type =typename State::type;
TRY-SET-VALUE(rcvr, variant_type(decayed-tuple<Args...>{std::forward<Args>(args)...}));
}else{
Tag()(std::move(rcvr), std::forward<Args>(args)...);
}}
The name stopped_as_optional denotes a pipeable sender adaptor object.
For a subexpression sndr, let Sndr be decltype((sndr)).
The expression stopped_as_optional(sndr) is expression-equivalent to:
transform_sender(get-domain-early(sndr), make-sender(stopped_as_optional, {}, sndr))
except that sndr is only evaluated once.
Let sndr and env be subexpressions
such that Sndr is decltype((sndr)) and
Env is decltype((env)).
If sender-for<Sndr, stopped_as_optional_t>
is false, or
if the type single-sender-value-type<Sndr, Env>
is ill-formed or void,
then the expression stopped_as_optional.transform_sender(sndr, env)
is ill-formed;
otherwise, it is equivalent to:
auto&&[_, _, child]= sndr;
using V =single-sender-value-type<Sndr, 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>()); });
The name stopped_as_error denotes a pipeable sender adaptor object.
For some subexpressions sndr and err,
let Sndr be decltype((sndr)) and
let Err be decltype((err)).
If the type Sndr does not satisfy sender or
if the type Err does not satisfy movable-value,
stopped_as_error(sndr, err) is ill-formed.
Otherwise, the expression stopped_as_error(sndr, err)
is expression-equivalent to:
transform_sender(get-domain-early(sndr), make-sender(stopped_as_error, err, sndr))
except that sndr is only evaluated once.
Let sndr and env be subexpressions
such that Sndr is decltype((sndr)) and
Env is decltype((env)).
If sender-for<Sndr, stopped_as_error_t> is false,
then the expression stopped_as_error.transform_sender(sndr, env)
is ill-formed;
otherwise, it is equivalent to:
auto&&[_, err, child]= sndr;
using E =decltype(auto(err));
return let_stopped(
std::forward_like<Sndr>(child),
[err = std::forward_like<Sndr>(err)]()mutablenoexcept(is_nothrow_move_constructible_v<E>){return just_error(std::move(err));
});