[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<Env>()))[.](#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<Tag>) 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<class Default = default_domain, class Sndr>
  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<T>(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<Default>(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*<Default>(sndr) is
a default-constructed prvalue of that type[.](#9.sentence-2)

Otherwise, *completion-domain*<Default>(sndr) is ill-formed[.](#9.sentence-3)

[ð](#itemdecl:2)

`template<class Tag, class Env, class Default>
  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<Default>(std​::​forward<Default>(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<class Sndr>
  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<class Sndr, class Env>
  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]")<Sndr, continues_on_t> 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*<void>(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 <functional> synopsis [functional.syn]") Fun>requires is_nothrow_move_constructible_v<Fun>struct *emplace-from* { Fun *fun*; // *exposition only*using type = *call-result-t*<Fun>; constexpr operator type() && noexcept([*nothrow-callable*](functional.syn#concept:nothrow-callable "22.10.2 Header <functional> synopsis [functional.syn]")<Fun>) {return std::move(fun)(); }constexpr type operator()() && noexcept([*nothrow-callable*](functional.syn#concept:nothrow-callable "22.10.2 Header <functional> synopsis [functional.syn]")<Fun>) {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)

template<class T0, class T1, …, class Tn>struct *product-type* { // *exposition only* T0 t0; // *exposition only* T1 t1; // *exposition only* ⋮
 Tn tn; // *exposition only*template<size_t I, class Self>constexpr decltype(auto) *get*(this Self&& self) noexcept; // *exposition only*template<class Self, class Fn>constexpr 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<size_t I, class Self>
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<Self>(ts...[I]);

template<class Self, class Fn>constexpr 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>(fn)(std::forward_like<Self>(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<template<class...> class T, class... Args>concept [*valid-specialization*](#concept:valid-specialization "33.9.2 Exposition-only entities [exec.snd.expos]") = // *exposition only*requires { typename T<Args...>; };}

[ð](#itemdecl:6)

`template<class Tag, class Data = see below, class... Child>
  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]")<Tag>

- [(24.2)](#24.2)

[*movable-value*](exec.general#concept:movable-value "33.1 General [exec.general]")<Data>

- [(24.3)](#24.3)

([sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")<Child> && ...)

- [(24.4)](#24.4)

[dependent_sender](exec.snd.concepts#concept:dependent_sender "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr> || [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr>,
where Sndr is *basic-sender*<Tag, Data,  
Child...> 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]")<Sndr> results in
an uncaught exception from
the evaluation of get_completion_signatures<Sndr>(),
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*<Tag, decay_t<Data>, decay_t<Child>...> 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 {template<class Tag>concept [*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]")<Tag, set_value_t> || [same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")<Tag, set_error_t> || [same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")<Tag, set_stopped_t>; 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*template<class Sndr, class... Env>static consteval void *check-types*(); // *exposition only*}; template<class Tag>struct *impls-for* : *default-impls* {}; // *exposition only*template<class Sndr, class Rcvr> // *exposition only*using *state-type* = decay_t<*call-result-t*<decltype(*impls-for*<tag_of_t<Sndr>>::*get-state*), Sndr, Rcvr&>>; template<class Index, class Sndr, class Rcvr> // *exposition only*using *env-type* = *call-result-t*<decltype(*impls-for*<tag_of_t<Sndr>>::*get-env*), Index, *state-type*<Sndr, Rcvr>&, const Rcvr&>; template<class Sndr>using *data-type* = decltype(declval<Sndr>().template *get*<1>()); // *exposition only*template<class Sndr, size_t I = 0>using *child-type* = decltype(declval<Sndr>().template *get*<I+2>()); // *exposition only*template<class Sndr>using *indices-for* = remove_reference_t<Sndr>::*indices-for*; // *exposition only*template<class Sndr, class Rcvr>struct *basic-state* { // *exposition only**basic-state*(Sndr&& sndr, Rcvr&& rcvr) noexcept(*see below*): *rcvr*(std::move(rcvr)) , *state*(*impls-for*<tag_of_t<Sndr>>::*get-state*(std::forward<Sndr>(sndr), *rcvr*)) { } Rcvr *rcvr*; // *exposition only**state-type*<Sndr, Rcvr> *state*; // *exposition only*}; template<class Sndr, class Rcvr, class Index>requires [*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<Sndr>; // *exposition only*using *state-t* = *state-type*<Sndr, Rcvr>; // *exposition only*static constexpr const auto& *complete* = *impls-for*<*tag-t*>::*complete*; // *exposition only*template<class... Args>requires [*callable*](functional.syn#concept:callable "22.10.2 Header <functional> synopsis [functional.syn]")<decltype(*complete*), Index, *state-t*&, Rcvr&, set_value_t, Args...>void set_value(Args&&... args) && noexcept {*complete*(Index(), op->*state*, op->*rcvr*, set_value_t(), std::forward<Args>(args)...); }template<class Error>requires [*callable*](functional.syn#concept:callable "22.10.2 Header <functional> synopsis [functional.syn]")<decltype(*complete*), Index, *state-t*&, Rcvr&, set_error_t, Error>void set_error(Error&& err) && noexcept {*complete*(Index(), op->*state*, op->*rcvr*, set_error_t(), std::forward<Error>(err)); }void set_stopped() && noexceptrequires [*callable*](functional.syn#concept:callable "22.10.2 Header <functional> synopsis [functional.syn]")<decltype(*complete*), Index, *state-t*&, Rcvr&, set_stopped_t> {*complete*(Index(), op->*state*, op->*rcvr*, set_stopped_t()); }auto get_env() const noexcept -> *env-type*<Index, Sndr, Rcvr> {return *impls-for*<tag-t>::*get-env*(Index(), op->*state*, op->*rcvr*); }*basic-state*<Sndr, Rcvr>* *op*; // *exposition only*}; constexpr auto *connect-all* = *see below*; // *exposition only*template<class Sndr, class Rcvr>using *connect-all-result* = *call-result-t*< // *exposition only*decltype(*connect-all*), *basic-state*<Sndr, Rcvr>*, Sndr, *indices-for*<Sndr>>; template<class Sndr, class Rcvr>requires [*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*<Sndr, Rcvr> { // *exposition only*using operation_state_concept = operation_state_t; using *tag-t* = tag_of_t<Sndr>; // *exposition only**connect-all-result*<Sndr, Rcvr> *inner-ops*; // *exposition only**basic-operation*(Sndr&& sndr, Rcvr&& rcvr) noexcept(*see below*) // *exposition only*: *basic-state*<Sndr, Rcvr>(std::forward<Sndr>(sndr), std::move(rcvr)), *inner-ops*(*connect-all*(this, std::forward<Sndr>(sndr), *indices-for*<Sndr>())){}void start() & noexcept {auto& [...ops] = *inner-ops*; *impls-for*<tag-t>::*start*(this->*state*, this->*rcvr*, ops...); }}; template<class Tag, class Data, class... Child>struct *basic-sender* : *product-type*<Tag, Data, Child...> { // *exposition only*using sender_concept = sender_t; using *indices-for* = index_sequence_for<Child...>; // *exposition only*decltype(auto) get_env() const noexcept {auto& [_, data, ...child] = *this; return *impls-for*<Tag>::*get-attrs*(data, child...); }template<[*decays-to*](execution.syn#concept:decays-to "33.4 Header <execution> 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*<Self, Rcvr> {return {std::forward<Self>(self), std::move(rcvr)}; }template<[*decays-to*](execution.syn#concept:decays-to "33.4 Header <execution> 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<Rcvr> &&[*nothrow-callable*](functional.syn#concept:nothrow-callable "22.10.2 Header <functional> synopsis [functional.syn]")<decltype(*impls-for*<tag_of_t<Sndr>>::*get-state*), Sndr, Rcvr&> &&([same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")<*state-type*<Sndr, Rcvr>, *get-state-result*> || is_nothrow_constructible_v<*state-type*<Sndr, Rcvr>, *get-state-result*>) where *get-state-result* is*call-result-t*<decltype(*impls-for*<tag_of_t<Sndr>>::*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)

`[]<class Sndr, class Rcvr, size_t... Is>(
  basic-state<Sndr, Rcvr>* op, Sndr&& sndr, index_sequence<Is...>) noexcept(see below)
    -> decltype(auto) {
    auto& [_, data, ...child] = sndr;
    return product-type{connect(
      std::forward_like<Sndr>(child),
      basic-receiver<Sndr, Rcvr, integral_constant<size_t, Is>>{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>, Self, Rcvr> &&noexcept(*connect-all*(this, std::forward<Sndr>(sndr), *indices-for*<Sndr>()))

[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>, 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:[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) noexcept -> decltype(auto) {auto& [_, data, ...child] = sndr; return *allocator-aware-forward*(std::forward_like<Sndr>(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:[]<class Index, class Rcvr, class Tag, class... Args>( Index, auto& state, Rcvr& rcvr, Tag, Args&&... args) noexcept-> void requires [*callable*](functional.syn#concept:callable "22.10.2 Header <functional> synopsis [functional.syn]")<Tag, Rcvr, Args...> {static_assert(Index::value == 0);
 Tag()(std::move(rcvr), std::forward<Args>(args)...);}

[ð](#lib:check-types,default-impls)

`template<class Sndr, class... Env>
  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*<Sndr>[.](#40.sentence-1)

[41](#41)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1984)

*Effects*: Equivalent to:(get_completion_signatures<*child-type*<Sndr, Is>, *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*<T>​::​*check-types*<S, E...>()[.](#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<class Tag, class Data, class... Child>
  template<class Sndr, class... Env>
    constexpr auto basic-sender<Tag, Data, Child...>::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*<Tag>​::​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<Sndr, Rcvr>[.](#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)

template<class... Fns>struct *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; template<class Sndr>static 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*([]<class Tag, class... Ts>(Tag(*)(Ts...)) {if constexpr (!(is_constructible_v<decay_t<Ts>, Ts> &&...))throw *unspecified-exception*(); });} where *unspecified-exception* is
a type derived from exception[.](#48.sentence-1)

[ð](#itemdecl:10)

`template<class T, class Context>
  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<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<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<T>(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<decltype(e)>(std::forward_like<T>(e), *alloc*) where e is the corresponding element of obj,

- [(50.3)](#50.3)

otherwise, returns make_obj_using_allocator<P>(std​::​forward<T>(obj), *alloc*)[.](#50.sentence-1)
