[exec.snd.expos] # 33 Execution control library [[exec]](./#exec) ## 33.9 Senders [[exec.snd]](exec.snd#expos) ### 33.9.2 Exposition-only entities [exec.snd.expos] [1](#1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1373) Subclause [[exec.snd]](exec.snd "33.9 Senders") makes use of the following exposition-only entities[.](#1.sentence-1) [2](#2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1376) For a queryable object env,*FWD-ENV*(env) is an expression whose type satisfies [*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") such that for a query object q and a pack of subexpressions as, the expression *FWD-ENV*(env).query(q, as...) is ill-formed if forwarding_query(q) is false; otherwise, it is expression-equivalent to env.query(q, as...)[.](#2.sentence-1) The type *FWD-ENV-T*(Env) isdecltype(*FWD-ENV*(declval()))[.](#2.sentence-2) [3](#3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1390) For a query object q and a subexpression v,*MAKE-ENV*(q, v) is an expression env whose type satisfies [*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") such that the result of env.query(q) has a value equal to v ([[concepts.equality]](concepts.equality "18.2 Equality preservation"))[.](#3.sentence-1) Unless otherwise stated, the object to which env.query(q) refers remains valid while env remains valid[.](#3.sentence-2) [4](#4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1400) For two queryable objects env1 and env2, a query object q, and a pack of subexpressions as,*JOIN-ENV*(env1, env2) is an expression env3 whose type satisfies [*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") such that env3.query(q, as...) is expression-equivalent to: - [(4.1)](#4.1) env1.query(q, as...) if that expression is well-formed, - [(4.2)](#4.2) otherwise, env2.query(q, as...) if that expression is well-formed, - [(4.3)](#4.3) otherwise, env3.query(q, as...) is ill-formed[.](#4.sentence-1) [5](#5) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1416) The results of *FWD-ENV*, *MAKE-ENV*, and *JOIN-ENV* can be context-dependent; i.e., they can evaluate to expressions with different types and value categories in different contexts for the same arguments[.](#5.sentence-1) [6](#6) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1423) For a scheduler sch,*SCHED-ATTRS*(sch) is an expression o1 whose type satisfies [*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") such that o1.query(get_completion_scheduler) is an expression with the same type and value as sch where Tag is one of set_value_t or set_stopped_t, and such that o1.query(get_domain) is expression-equivalent tosch.query(get_domain)[.](#6.sentence-1) *SCHED-ENV*(sch) is an expression o2 whose type satisfies [*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") such that o2.query(get_scheduler) is a prvalue with the same type and value as sch, and such that o2.query(get_domain) is expression-equivalent tosch.query(get_domain)[.](#6.sentence-2) [7](#7) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1439) For two subexpressions rcvr and expr,*SET-VALUE*(rcvr, expr) is expression-equivalent to(expr, set_value(std​::​move(rcvr))) if the type of expr is void; otherwise, set_value(std​::​move(rcvr), expr)[.](#7.sentence-1) *TRY-EVAL*(rcvr, expr) is equivalent to:try { expr;} catch(...) { set_error(std::move(rcvr), current_exception());} if expr is potentially-throwing; otherwise, expr[.](#7.sentence-2) *TRY-SET-VALUE*(rcvr, expr) is*TRY-EVAL*(rcvr, *SET-VALUE*(rcvr, expr)) except that rcvr is evaluated only once[.](#7.sentence-3) [🔗](#itemdecl:1) `template constexpr auto completion-domain(const Sndr& sndr) noexcept; ` [8](#8) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1466) *COMPL-DOMAIN*(T) is the type of the expressionget_domain(get_completion_scheduler(get_env(sndr)))[.](#8.sentence-1) [9](#9) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1470) *Effects*: If all of the types*COMPL-DOMAIN*(set_value_t),*COMPL-DOMAIN*(set_error_t), and *COMPL-DOMAIN*(set_stopped_t) are ill-formed,completion-domain(sndr) is a default-constructed prvalue of type Default[.](#9.sentence-1) Otherwise, if they all share a common type ([[meta.trans.other]](meta.trans.other "21.3.9.7 Other transformations")) (ignoring those types that are ill-formed), then *completion-domain*(sndr) is a default-constructed prvalue of that type[.](#9.sentence-2) Otherwise, *completion-domain*(sndr) is ill-formed[.](#9.sentence-3) [🔗](#itemdecl:2) `template constexpr decltype(auto) query-with-default( Tag, const Env& env, Default&& value) noexcept(see below); ` [10](#10) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1492) Let e be the expression Tag()(env) if that expression is well-formed; otherwise, it is static_cast(std​::​forward(value))[.](#10.sentence-1) [11](#11) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1497) *Returns*: e[.](#11.sentence-1) [12](#12) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1501) *Remarks*: The expression in the noexcept clause is noexcept(e)[.](#12.sentence-1) [🔗](#itemdecl:3) `template constexpr auto get-domain-early(const Sndr& sndr) noexcept; ` [13](#13) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1512) *Effects*: Equivalent to:return Domain(); where Domain is the decayed type of the first of the following expressions that is well-formed: - [(13.1)](#13.1) get_domain(get_env(sndr)) - [(13.2)](#13.2) *completion-domain*(sndr) - [(13.3)](#13.3) default_domain() [🔗](#itemdecl:4) `template constexpr auto get-domain-late(const Sndr& sndr, const Env& env) noexcept; ` [14](#14) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1533) *Effects*: Equivalent to: - [(14.1)](#14.1) If [*sender-for*](exec.snd.concepts#concept:sender-for "33.9.3 Sender concepts [exec.snd.concepts]") is true, thenreturn Domain(); where Domain is the type of the following expression:[] {auto [_, sch, _] = sndr; return *query-with-default*(get_domain, sch, default_domain());}(); [*Note [1](#note-1)*: The continues_on algorithm works in tandem with schedule_from ([[exec.schedule.from]](exec.schedule.from "33.9.12.7 execution​::​schedule_­from")) to give scheduler authors a way to customize both how to transition onto (continues_on) and off of (schedule_from) a given execution context[.](#14.1.sentence-1) Thus, continues_on ignores the domain of the predecessor and uses the domain of the destination scheduler to select a customization, a property that is unique to continues_on[.](#14.1.sentence-2) That is why it is given special treatment here[.](#14.1.sentence-3) — *end note*] - [(14.2)](#14.2) Otherwise,return Domain(); where Domain is the first of the following expressions that is well-formed and whose type is not void: * [(14.2.1)](#14.2.1) get_domain(get_env(sndr)) * [(14.2.2)](#14.2.2) *completion-domain*(sndr) * [(14.2.3)](#14.2.3) get_domain(env) * [(14.2.4)](#14.2.4) get_domain(get_scheduler(env)) * [(14.2.5)](#14.2.5) default_domain() [15](#15) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1577) template<[*callable*](functional.syn#concept:callable "22.10.2 Header synopsis [functional.syn]") Fun>requires is_nothrow_move_constructible_vstruct *emplace-from* { Fun *fun*; // *exposition only*using type = *call-result-t*; constexpr operator type() && noexcept([*nothrow-callable*](functional.syn#concept:nothrow-callable "22.10.2 Header synopsis [functional.syn]")) {return std::move(fun)(); }constexpr type operator()() && noexcept([*nothrow-callable*](functional.syn#concept:nothrow-callable "22.10.2 Header synopsis [functional.syn]")) {return std::move(fun)(); }}; [*Note [2](#note-2)*: *emplace-from* is used to emplace non-movable types into tuple, optional, variant, and similar types[.](#15.sentence-1) — *end note*] [16](#16) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1599) struct *on-stop-request* { inplace_stop_source& *stop-src*; // *exposition only*void operator()() noexcept { *stop-src*.request_stop(); }}; [17](#17) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1607) templatestruct *product-type* { // *exposition only* T0 t0; // *exposition only* T1 t1; // *exposition only* ⋮ Tn tn; // *exposition only*templateconstexpr decltype(auto) *get*(this Self&& self) noexcept; // *exposition only*templateconstexpr decltype(auto) *apply*(this Self&& self, Fn&& fn) // *exposition only*noexcept(*see below*);}; [18](#18) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1625) [*Note [3](#note-3)*: *product-type* is presented here in pseudo-code form for the sake of exposition[.](#18.sentence-1) It can be approximated in standard C++ with a tuple-like implementation that takes care to keep the type an aggregate that can be used as the initializer of a structured binding declaration[.](#18.sentence-2) — *end note*] [*Note [4](#note-4)*: An expression of type *product-type* is usable as the initializer of a structured binding declaration ([[dcl.struct.bind]](dcl.struct.bind "9.7 Structured binding declarations"))[.](#18.sentence-3) — *end note*] [🔗](#itemdecl:5) `template constexpr decltype(auto) get(this Self&& self) noexcept; ` [19](#19) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1644) *Effects*: Equivalent to:auto& [...ts] = self;return std::forward_like(ts...[I]); templateconstexpr decltype(auto) *apply*(this Self&& self, Fn&& fn) noexcept(*see below*); [20](#20) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1659) *Constraints*: The expression in the return statement below is well-formed[.](#20.sentence-1) [21](#21) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1663) *Effects*: Equivalent to:auto& [...ts] = self;return std::forward(fn)(std::forward_like(ts)...); [22](#22) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1671) *Remarks*: The expression in the noexcept clause is true if the return statement above is not potentially throwing; otherwise, false[.](#22.sentence-1) [23](#23) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1678) Let [*valid-specialization*](#concept:valid-specialization "33.9.2 Exposition-only entities [exec.snd.expos]") be the following concept:namespace std::execution {template class T, class... Args>concept [*valid-specialization*](#concept:valid-specialization "33.9.2 Exposition-only entities [exec.snd.expos]") = // *exposition only*requires { typename T; };} [🔗](#itemdecl:6) `template constexpr auto make-sender(Tag tag, Data&& data, Child&&... child); ` [24](#24) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1694) *Mandates*: The following expressions are true: - [(24.1)](#24.1) [semiregular](concepts.object#concept:semiregular "18.6 Object concepts [concepts.object]") - [(24.2)](#24.2) [*movable-value*](exec.general#concept:movable-value "33.1 General [exec.general]") - [(24.3)](#24.3) ([sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") && ...) - [(24.4)](#24.4) [dependent_sender](exec.snd.concepts#concept:dependent_sender "33.9.3 Sender concepts [exec.snd.concepts]") || [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]"), where Sndr is *basic-sender* as defined below[.](#24.sentence-1) *Recommended practice*: If evaluation of [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]") results in an uncaught exception from the evaluation of get_completion_signatures(), the implementation should include information about that exception in the resulting diagnostic[.](#24.4.sentence-2) [25](#25) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1714) *Returns*: A prvalue of type *basic-sender*, decay_t...> that has been direct-list-initialized with the forwarded arguments, where *basic-sender* is the following exposition-only class template except as noted below[.](#25.sentence-1) [26](#26) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1722) *Remarks*: The default template argument for the Data template parameter denotes an unspecified empty trivially copyable class type that models [semiregular](concepts.object#concept:semiregular "18.6 Object concepts [concepts.object]")[.](#26.sentence-1) namespace std::execution {templateconcept [*completion-tag*](#concept:completion-tag "33.9.2 Exposition-only entities [exec.snd.expos]") = // *exposition only*[same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]") || [same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]") || [same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]"); struct *default-impls* { // *exposition only*static constexpr auto *get-attrs* = *see below*; // *exposition only*static constexpr auto *get-env* = *see below*; // *exposition only*static constexpr auto *get-state* = *see below*; // *exposition only*static constexpr auto *start* = *see below*; // *exposition only*static constexpr auto *complete* = *see below*; // *exposition only*templatestatic consteval void *check-types*(); // *exposition only*}; templatestruct *impls-for* : *default-impls* {}; // *exposition only*template // *exposition only*using *state-type* = decay_t<*call-result-t*>::*get-state*), Sndr, Rcvr&>>; template // *exposition only*using *env-type* = *call-result-t*>::*get-env*), Index, *state-type*&, const Rcvr&>; templateusing *data-type* = decltype(declval().template *get*<1>()); // *exposition only*templateusing *child-type* = decltype(declval().template *get*()); // *exposition only*templateusing *indices-for* = remove_reference_t::*indices-for*; // *exposition only*templatestruct *basic-state* { // *exposition only**basic-state*(Sndr&& sndr, Rcvr&& rcvr) noexcept(*see below*): *rcvr*(std::move(rcvr)) , *state*(*impls-for*>::*get-state*(std::forward(sndr), *rcvr*)) { } Rcvr *rcvr*; // *exposition only**state-type* *state*; // *exposition only*}; templaterequires [*valid-specialization*](#concept:valid-specialization "33.9.2 Exposition-only entities [exec.snd.expos]")<*env-type*, Index, Sndr, Rcvr>struct *basic-receiver* { // *exposition only*using receiver_concept = receiver_t; using *tag-t* = tag_of_t; // *exposition only*using *state-t* = *state-type*; // *exposition only*static constexpr const auto& *complete* = *impls-for*<*tag-t*>::*complete*; // *exposition only*templaterequires [*callable*](functional.syn#concept:callable "22.10.2 Header synopsis [functional.syn]")void set_value(Args&&... args) && noexcept {*complete*(Index(), op->*state*, op->*rcvr*, set_value_t(), std::forward(args)...); }templaterequires [*callable*](functional.syn#concept:callable "22.10.2 Header synopsis [functional.syn]")void set_error(Error&& err) && noexcept {*complete*(Index(), op->*state*, op->*rcvr*, set_error_t(), std::forward(err)); }void set_stopped() && noexceptrequires [*callable*](functional.syn#concept:callable "22.10.2 Header synopsis [functional.syn]") {*complete*(Index(), op->*state*, op->*rcvr*, set_stopped_t()); }auto get_env() const noexcept -> *env-type* {return *impls-for*::*get-env*(Index(), op->*state*, op->*rcvr*); }*basic-state** *op*; // *exposition only*}; constexpr auto *connect-all* = *see below*; // *exposition only*templateusing *connect-all-result* = *call-result-t*< // *exposition only*decltype(*connect-all*), *basic-state**, Sndr, *indices-for*>; templaterequires [*valid-specialization*](#concept:valid-specialization "33.9.2 Exposition-only entities [exec.snd.expos]")<*state-type*, Sndr, Rcvr> &&[*valid-specialization*](#concept:valid-specialization "33.9.2 Exposition-only entities [exec.snd.expos]")<*connect-all-result*, Sndr, Rcvr>struct *basic-operation* : *basic-state* { // *exposition only*using operation_state_concept = operation_state_t; using *tag-t* = tag_of_t; // *exposition only**connect-all-result* *inner-ops*; // *exposition only**basic-operation*(Sndr&& sndr, Rcvr&& rcvr) noexcept(*see below*) // *exposition only*: *basic-state*(std::forward(sndr), std::move(rcvr)), *inner-ops*(*connect-all*(this, std::forward(sndr), *indices-for*())){}void start() & noexcept {auto& [...ops] = *inner-ops*; *impls-for*::*start*(this->*state*, this->*rcvr*, ops...); }}; templatestruct *basic-sender* : *product-type* { // *exposition only*using sender_concept = sender_t; using *indices-for* = index_sequence_for; // *exposition only*decltype(auto) get_env() const noexcept {auto& [_, data, ...child] = *this; return *impls-for*::*get-attrs*(data, child...); }template<[*decays-to*](execution.syn#concept:decays-to "33.4 Header synopsis [execution.syn]")<*basic-sender*> Self, [receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") Rcvr>auto connect(this Self&& self, Rcvr rcvr) noexcept(*see below*)-> *basic-operation* {return {std::forward(self), std::move(rcvr)}; }template<[*decays-to*](execution.syn#concept:decays-to "33.4 Header synopsis [execution.syn]")<*basic-sender*> Self, class... Env>static constexpr auto get_completion_signatures(); };} [27](#27) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1857) It is unspecified whether a specialization of *basic-sender* is an aggregate[.](#27.sentence-1) [28](#28) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1861) An expression of type *basic-sender* is usable as the initializer of a structured binding declaration ([[dcl.struct.bind]](dcl.struct.bind "9.7 Structured binding declarations"))[.](#28.sentence-1) [29](#29) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1865) The expression in the noexcept clause of the constructor of *basic-state* isis_nothrow_move_constructible_v &&[*nothrow-callable*](functional.syn#concept:nothrow-callable "22.10.2 Header synopsis [functional.syn]")>::*get-state*), Sndr, Rcvr&> &&([same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")<*state-type*, *get-state-result*> || is_nothrow_constructible_v<*state-type*, *get-state-result*>) where *get-state-result* is*call-result-t*>::*get-state*), Sndr, Rcvr&>. [30](#30) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1879) The object *connect-all* is initialized with a callable object equivalent to the following lambda: [🔗](#itemdecl:7) `[]( basic-state* op, Sndr&& sndr, index_sequence) noexcept(see below) -> decltype(auto) { auto& [_, data, ...child] = sndr; return product-type{connect( std::forward_like(child), basic-receiver>{op})...}; } ` [31](#31) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1894) *Constraints*: The expression in the return statement is well-formed[.](#31.sentence-1) [32](#32) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1898) *Remarks*: The expression in the noexcept clause is true if the return statement is not potentially throwing; otherwise, false[.](#32.sentence-1) [33](#33) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1905) The expression in the noexcept clause of the constructor of *basic-operation* is:is_nothrow_constructible_v<*basic-state*, Self, Rcvr> &&noexcept(*connect-all*(this, std::forward(sndr), *indices-for*())) [34](#34) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1913) The expression in the noexcept clause of the connect member function of *basic-sender* is:is_nothrow_constructible_v<*basic-operation*, Self, Rcvr> [35](#35) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1920) The member *default-impls*​::​*get-attrs* is initialized with a callable object equivalent to the following lambda:[](const auto&, const auto&... child) noexcept -> decltype(auto) {if constexpr (sizeof...(child) == 1)return (*FWD-ENV*(get_env(child)), ...); elsereturn env<>();} [36](#36) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1932) The member *default-impls*​::​*get-env* is initialized with a callable object equivalent to the following lambda:[](auto, auto&, const auto& rcvr) noexcept -> decltype(auto) {return *FWD-ENV*(get_env(rcvr));} [37](#37) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1941) The member *default-impls*​::​*get-state* is initialized with a callable object equivalent to the following lambda:[](Sndr&& sndr, Rcvr& rcvr) noexcept -> decltype(auto) {auto& [_, data, ...child] = sndr; return *allocator-aware-forward*(std::forward_like(data), rcvr);} [38](#38) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1951) The member *default-impls*​::​*start* is initialized with a callable object equivalent to the following lambda:[](auto&, auto&, auto&... ops) noexcept -> void {(execution::start(ops), ...);} [39](#39) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1960) The member *default-impls*​::​*complete* is initialized with a callable object equivalent to the following lambda:[]( Index, auto& state, Rcvr& rcvr, Tag, Args&&... args) noexcept-> void requires [*callable*](functional.syn#concept:callable "22.10.2 Header synopsis [functional.syn]") {static_assert(Index::value == 0); Tag()(std::move(rcvr), std::forward(args)...);} [🔗](#lib:check-types,default-impls) `template static consteval void default-impls::check-types(); ` [40](#40) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1979) Let Is be the pack of integral template arguments of the integer_sequence specialization denoted by*indices-for*[.](#40.sentence-1) [41](#41) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1984) *Effects*: Equivalent to:(get_completion_signatures<*child-type*, *FWD-ENV-T*(Env)...>(), ...); [42](#42) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1991) [*Note [5](#note-5)*: For any types T and S, and pack E, let e be the expression*impls-for*​::​*check-types*()[.](#42.sentence-1) Then exactly one of the following is true: - [(42.1)](#42.1) e is ill-formed, or - [(42.2)](#42.2) the evaluation of e exits with an exception, or - [(42.3)](#42.3) e is a core constant expression[.](#42.sentence-2) When e is a core constant expression, the pack S, E... uniquely determines a set of completion signatures[.](#42.sentence-3) — *end note*] [🔗](#lib:get_completion_signatures,basic-sender) `template template constexpr auto basic-sender::get_completion_signatures(); ` [43](#43) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2015) Let Rcvr be the type of a receiver whose environment has type E, whereE is the first type in the list Env..., env<>[.](#43.sentence-1) Let *CHECK-TYPES*() be the expression*impls-for*​::​template *check-types*< Sndr, E>(), and let CS be a type determined as follows: - [(43.1)](#43.1) If *CHECK-TYPES*() is a core constant expression, let op be an lvalue subexpression whose type is connect_result_t[.](#43.1.sentence-1) Then CS is the specialization of completion_signatures the set of whose template arguments correspond to the set of completion operations that are potentially evaluated ([[basic.def.odr]](basic.def.odr "6.3 One-definition rule")) as a result of evaluating op.start()[.](#43.1.sentence-2) - [(43.2)](#43.2) Otherwise, CS is completion_signatures<>[.](#43.2.sentence-1) [44](#44) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2038) *Constraints*: *CHECK-TYPES*() is a well-formed expression[.](#44.sentence-1) [45](#45) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2042) *Effects*: Equivalent to:*CHECK-TYPES*();return CS(); [46](#46) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2051) templatestruct *overload-set* : Fns... {using Fns::operator()...;}; [47](#47) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2061) struct *not-a-sender* {using sender_concept = sender_t; templatestatic consteval auto get_completion_signatures() -> completion_signatures<> {throw *unspecified-exception*(); }}; where *unspecified-exception* is a type derived from exception[.](#47.sentence-1) [48](#48) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2078) constexpr void *decay-copyable-result-datums*(auto cs) { cs.*for-each*([](Tag(*)(Ts...)) {if constexpr (!(is_constructible_v, Ts> &&...))throw *unspecified-exception*(); });} where *unspecified-exception* is a type derived from exception[.](#48.sentence-1) [🔗](#itemdecl:10) `template decltype(auto) allocator-aware-forward(T&& obj, Context&& context); // exposition only ` [49](#49) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2098) *allocator-aware-forward* is an exposition-only function template used to either create a new object of type remove_cvref_t from obj or forward obj depending on whether an allocator is available[.](#49.sentence-1) If the environment associated with context provides an allocator (i.e., the expression get_allocator(get_env(context)) is valid), let *alloc* be the result of this expression and let P be remove_cvref_t[.](#49.sentence-2) [50](#50) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2108) *Returns*: - [(50.1)](#50.1) If *alloc* is not defined, returns std​::​forward(obj), - [(50.2)](#50.2) otherwise if P is a specialization of *product-type*, returns an object of type P whose elements are initialized usingmake_obj_using_allocator(std::forward_like(e), *alloc*) where e is the corresponding element of obj, - [(50.3)](#50.3) otherwise, returns make_obj_using_allocator

(std​::​forward(obj), *alloc*)[.](#50.sentence-1)