[exec.adapt]

# 33 Execution control library [[exec]](./#exec)

## 33.9 Senders [[exec.snd]](exec.snd#exec.adapt)

### 33.9.12 Sender adaptors [exec.adapt]

#### [33.9.12.1](#general) General [[exec.adapt.general]](exec.adapt.general)

[1](#general-1)

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

Subclause [exec.adapt] specifies a set of sender adaptors[.](#general-1.sentence-1)

[2](#general-2)

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

The bitwise inclusive or operator is overloaded
for the purpose of creating sender chains[.](#general-2.sentence-1)

The adaptors also support function call syntax with equivalent semantics[.](#general-2.sentence-2)

[3](#general-3)

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

Unless otherwise specified:

- [(3.1)](#general-3.1)

  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[.](#general-3.1.sentence-1)

- [(3.2)](#general-3.2)

  A parent sender ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations")) with a single child sender sndr has
an associated attribute object equal to*FWD-ENV*(get_env(sndr)) ([[exec.fwd.env]](exec.fwd.env "33.5.1 forwarding_­query"))[.](#general-3.2.sentence-1)

- [(3.3)](#general-3.3)

  A parent sender with more than one child sender has
an associated attributes object equal to env<>{}[.](#general-3.3.sentence-1)

- [(3.4)](#general-3.4)

  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))[.](#general-3.4.sentence-1)

- [(3.5)](#general-3.5)

  An adaptor whose child senders are all non-dependent ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))
is itself non-dependent[.](#general-3.5.sentence-1)

- [(3.6)](#general-3.6)

  These requirements apply to any function
that is selected by the implementation of the sender adaptor[.](#general-3.6.sentence-1)

- [(3.7)](#general-3.7)

  *Recommended practice*: Implementations should use
the completion signatures of the adaptors
to communicate type errors to users and
to propagate any such type errors from child senders[.](#general-3.7.sentence-1)

[4](#general-4)

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

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[.](#general-4.sentence-1)

#### [33.9.12.2](#obj) Closure objects [[exec.adapt.obj]](exec.adapt.obj)

[1](#obj-1)

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

A [*pipeable sender adaptor closure object*](#def:sender_adaptor_closure_object,pipeable "33.9.12.2 Closure objects [exec.adapt.obj]") is a function object
that accepts one or more [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") arguments and returns a [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")[.](#obj-1.sentence-1)

For a pipeable sender adaptor closure object c and
an expression sndr such that decltype((sndr)) models [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"),
the following expressions are equivalent and yield a [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"):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]](func.require "22.10.4 Requirements"))
with the following properties:

- [(1.1)](#obj-1.1)

  Its target object is an object d2 of type decltype(auto(d)) direct-non-list-initialized with d[.](#obj-1.1.sentence-1)

- [(1.2)](#obj-1.2)

  It has one bound argument entity,
an object c2 of type decltype(auto(c)) direct-non-list-initialized with c[.](#obj-1.2.sentence-1)

- [(1.3)](#obj-1.3)

  Its call pattern is d2(c2(arg)),
where arg is the argument used in a function call expression of e[.](#obj-1.3.sentence-1)

The expression c | d is well-formed if and only if
the initializations of the state entities ([[func.def]](func.def "22.10.3 Definitions")) of e are all well-formed[.](#obj-1.sentence-5)

[2](#obj-2)

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

An object t of type T is
a pipeable sender adaptor closure object
if T models [derived_from](concept.derived#concept:derived_from "18.4.3 Concept derived_­from [concept.derived]")<sender_adaptor_closure<T>>,T has no other base classes
of type sender_adaptor_closure<U> for any other type U, andT does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")[.](#obj-2.sentence-1)

[3](#obj-3)

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

The template parameter D for sender_adaptor_closure can be
an incomplete type[.](#obj-3.sentence-1)

Before any expression of type cv D appears as
an operand to the | operator,D shall be complete and
model [derived_from](concept.derived#concept:derived_from "18.4.3 Concept derived_­from [concept.derived]")<sender_adaptor_closure<D>>[.](#obj-3.sentence-2)

The behavior of an expression involving an object of type cv D as an operand to the | operator is undefined
if overload resolution selects a program-defined operator| function[.](#obj-3.sentence-3)

[4](#obj-4)

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

A [*pipeable sender adaptor object*](#def:sender_adaptor_object,pipeable "33.9.12.2 Closure objects [exec.adapt.obj]") is a customization point object
that accepts a [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") as its first argument and
returns a [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")[.](#obj-4.sentence-1)

If a pipeable sender adaptor object accepts only one argument,
then it is a pipeable sender adaptor closure object[.](#obj-4.sentence-2)

[5](#obj-5)

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

If a pipeable sender adaptor object adaptor accepts more than one argument,
then let sndr be an expression
such that decltype((sndr)) models [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"),
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))...[.](#obj-5.sentence-1)

The expression adaptor(args...) produces
a pipeable sender adaptor closure object f that is a perfect forwarding call wrapper with the following properties:

- [(5.1)](#obj-5.1)

  Its target object is a copy of adaptor[.](#obj-5.1.sentence-1)

- [(5.2)](#obj-5.2)

  Its bound argument entities bound_args consist of
objects of types BoundArgs... direct-non-list-initialized withstd​::​forward<decltype((args))>(args)..., respectively[.](#obj-5.2.sentence-1)

- [(5.3)](#obj-5.3)

  Its call pattern is adaptor(rcvr, bound_args...),
where rcvr is
the argument used in a function call expression of f[.](#obj-5.3.sentence-1)

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[.](#obj-5.sentence-3)

#### [33.9.12.3](#exec.write.env) execution​::​write_env [[exec.write.env]](exec.write.env)

[1](#exec.write.env-1)

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

write_env is a sender adaptor
that accepts a sender and a queryable object, and
that returns a sender that,
when connected with a receiver rcvr,
connects the adapted sender with a receiver
whose execution environment is the result of
joining the [*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") object
to the result of get_env(rcvr)[.](#exec.write.env-1.sentence-1)

[2](#exec.write.env-2)

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

write_env is a customization point object[.](#exec.write.env-2.sentence-1)

For some subexpressions sndr and env,
if decltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") or
if decltype((env)) does not satisfy [*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]"),
the expression write_env(sndr, env) is ill-formed[.](#exec.write.env-2.sentence-2)

Otherwise, it is expression-equivalent to*make-sender*(write_env, env, sndr)[.](#exec.write.env-2.sentence-3)

[3](#exec.write.env-3)

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

Let *write-env-t* denote the type decltype(auto(write_env))[.](#exec.write.env-3.sentence-1)

The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
is specialized for *write-env-t* as follows:

[ð](#lib:impls-for%3cwrite-env-t%3e)

template<>struct *impls-for*<*write-env-t*> : *default-impls* {static constexpr auto *join-env*(const auto& state, const auto& env) noexcept {return *see below*; }static constexpr auto *get-env* =[](auto, const auto& state, const auto& rcvr) noexcept {return *join-env*(state, *FWD-ENV*(get_env(rcvr))); }; template<class Sndr, class... Env>static consteval void *check-types*();};

[4](#exec.write.env-4)

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

Invocation of*impls-for*<*write-env-t*>​::​*join-env* returns an object e such that

- [(4.1)](#exec.write.env-4.1)

decltype(e) models [*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") and

- [(4.2)](#exec.write.env-4.2)

given a query object q,
the expression e.query(q) is expression-equivalent
to state.query(q) if that expression is valid,
otherwise, e.query(q) is expression-equivalent
to env.query(q)[.](#exec.write.env-4.sentence-1)

[5](#exec.write.env-5)

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

For a type Sndr and a pack of types Env,
let State be *data-type*<Sndr> and
let JoinEnv be the packdecltype(*join-env*(declval<State>(), *FWD-ENV*(declval<Env>())))[.](#exec.write.env-5.sentence-1)

Then *impls-for*<*write-env-​t*>​::​*check-types*<Sndr, Env...>() is expression-equivalent toget_completion_signatures<*child-  
type*<Sndr>, JoinEnv...>()[.](#exec.write.env-5.sentence-2)

#### [33.9.12.4](#exec.unstoppable) execution​::​unstoppable [[exec.unstoppable]](exec.unstoppable)

[1](#exec.unstoppable-1)

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

unstoppable is a sender adaptor
that connects its inner sender
with a receiver that has the execution environment of the outer receiver
but with an object of type never_stop_token as the result of the get_stop_token query[.](#exec.unstoppable-1.sentence-1)

[2](#exec.unstoppable-2)

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

For a subexpression sndr,unstoppable(sndr) is expression-equivalent towrite_env(sndr, prop(get_stop_token, never_stop_token{}))[.](#exec.unstoppable-2.sentence-1)

#### [33.9.12.5](#exec.starts.on) execution​::​starts_on [[exec.starts.on]](exec.starts.on)

[1](#exec.starts.on-1)

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

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[.](#exec.starts.on-1.sentence-1)

[2](#exec.starts.on-2)

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

The name starts_on denotes a customization point object[.](#exec.starts.on-2.sentence-1)

For subexpressions sch and sndr,
if decltype((  
sch)) does not satisfy [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]"), ordecltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"),starts_on(sch, sndr) is ill-formed[.](#exec.starts.on-2.sentence-2)

[3](#exec.starts.on-3)

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

Otherwise,
the expression starts_on(sch, sndr) is expression-equivalent to:transform_sender(*query-with-default*(get_domain, sch, default_domain()), *make-sender*(starts_on, sch, sndr)) except that sch is evaluated only once[.](#exec.starts.on-3.sentence-1)

[4](#exec.starts.on-4)

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

Let out_sndr and env be subexpressions
such that OutSndr is decltype((out_sndr))[.](#exec.starts.on-4.sentence-1)

If [*sender-for*](exec.snd.concepts#concept:sender-for "33.9.3 Sender concepts [exec.snd.concepts]")<OutSndr, starts_on_t> is false,
then the expressions starts_on.transform_env(out_sndr, env) andstarts_on.transform_sender(out_sndr, env) are ill-formed; otherwise

- [(4.1)](#exec.starts.on-4.1)

starts_on.transform_env(out_sndr, env) is equivalent to:auto&& [_, sch, _] = out_sndr;return *JOIN-ENV*(*SCHED-ENV*(sch), *FWD-ENV*(env));

- [(4.2)](#exec.starts.on-4.2)

starts_on.transform_sender(out_sndr, env) is equivalent to:auto&& [_, sch, sndr] = out_sndr;return let_value( schedule(sch), [sndr = std::forward_like<OutSndr>(sndr)]() mutablenoexcept(is_nothrow_move_constructible_v<decay_t<OutSndr>>) {return std::move(sndr); });

[5](#exec.starts.on-5)

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

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))[.](#exec.starts.on-5.sentence-1)

Let out_rcvr be a subexpression denoting a receiver
that has an environment of type Env such that [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<OutSndr, Env> is true[.](#exec.starts.on-5.sentence-2)

Let op be an lvalue referring to the operation state
that results from connecting out_sndr with out_rcvr[.](#exec.starts.on-5.sentence-3)

Calling start(op) shall start sndr on an execution agent of the associated execution resource of sch[.](#exec.starts.on-5.sentence-4)

If scheduling onto sch fails,
an error completion on out_rcvr shall be executed
on an unspecified execution agent[.](#exec.starts.on-5.sentence-5)

#### [33.9.12.6](#exec.continues.on) execution​::​continues_on [[exec.continues.on]](exec.continues.on)

[1](#exec.continues.on-1)

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

continues_on adapts a sender into one
that completes on the specified scheduler[.](#exec.continues.on-1.sentence-1)

[2](#exec.continues.on-2)

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

The name continues_on denotes a pipeable sender adaptor object[.](#exec.continues.on-2.sentence-1)

For subexpressions sch and sndr,
if decltype((sch)) does not satisfy [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]"), ordecltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"),continues_on(sndr, sch) is ill-formed[.](#exec.continues.on-2.sentence-2)

[3](#exec.continues.on-3)

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

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[.](#exec.continues.on-3.sentence-1)

[4](#exec.continues.on-4)

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

The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
is specialized for continues_on_t as follows:namespace std::execution {template<>struct *impls-for*<continues_on_t> : *default-impls* {static constexpr auto *get-attrs* =[](const auto& data, const auto& child) noexcept -> decltype(auto) {return *JOIN-ENV*(*SCHED-ATTRS*(data), *FWD-ENV*(get_env(child))); }; };}

[5](#exec.continues.on-5)

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

Let sndr and env be subexpressions
such that Sndr is decltype((sndr))[.](#exec.continues.on-5.sentence-1)

If [*sender-for*](exec.snd.concepts#concept:sender-for "33.9.3 Sender concepts [exec.snd.concepts]")<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));

[*Note [1](#exec.continues.on-note-1)*:

This causes the continues_on(sndr, sch) sender to becomeschedule_from(sch, sndr) when it is connected with a receiver
whose execution domain does not customize continues_on[.](#exec.continues.on-5.sentence-2)

â *end note*]

[6](#exec.continues.on-6)

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

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))[.](#exec.continues.on-6.sentence-1)

Let out_rcvr be a subexpression denoting a receiver
that has an environment of type Env such that [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<OutSndr, Env> is true[.](#exec.continues.on-6.sentence-2)

Let op be an lvalue referring to the operation state
that results from connecting out_sndr with out_rcvr[.](#exec.continues.on-6.sentence-3)

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[.](#exec.continues.on-6.sentence-4)

If scheduling onto sch fails,
an error completion on out_rcvr shall be executed
on an unspecified execution agent[.](#exec.continues.on-6.sentence-5)

#### [33.9.12.7](#exec.schedule.from) execution​::​schedule_from [[exec.schedule.from]](exec.schedule.from)

[1](#exec.schedule.from-1)

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

schedule_from schedules work dependent on the completion of a sender
onto a scheduler's associated execution resource[.](#exec.schedule.from-1.sentence-1)

[*Note [1](#exec.schedule.from-note-1)*:

schedule_from is not meant to be used in user code;
it is used in the implementation of continues_on[.](#exec.schedule.from-1.sentence-2)

â *end note*]

[2](#exec.schedule.from-2)

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

The name schedule_from denotes a customization point object[.](#exec.schedule.from-2.sentence-1)

For some subexpressions sch and sndr,
let Sch be decltype((sch)) andSndr be decltype((sndr))[.](#exec.schedule.from-2.sentence-2)

If Sch does not satisfy [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]"), orSndr does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"),schedule_from(sch, sndr) is ill-formed[.](#exec.schedule.from-2.sentence-3)

[3](#exec.schedule.from-3)

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

Otherwise,
the expression schedule_from(sch, sndr) is expression-equivalent to:transform_sender(*query-with-default*(get_domain, sch, default_domain()), *make-sender*(schedule_from, sch, sndr)) except that sch is evaluated only once[.](#exec.schedule.from-3.sentence-1)

[4](#exec.schedule.from-4)

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

The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
is specialized for schedule_from_t as follows:

[ð](#lib:impls-for%3cschedule_from_t%3e)

namespace std::execution {template<>struct *impls-for*<schedule_from_t> : *default-impls* {static constexpr auto *get-attrs* = *see below*; static constexpr auto *get-state* = *see below*; static constexpr auto *complete* = *see below*; template<class Sndr, class... Env>static consteval void *check-types*(); };}

[5](#exec.schedule.from-5)

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

The member *impls-for*<schedule_from_t>​::​*get-attrs* is initialized with a callable object equivalent to the following lambda:[](const auto& data, const auto& child) noexcept -> decltype(auto) {return *JOIN-ENV*(*SCHED-ATTRS*(data), *FWD-ENV*(get_env(child)));}

[6](#exec.schedule.from-6)

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

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*)requires [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<*child-type*<Sndr>, *FWD-ENV-T*(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>; constexpr bool nothrow = noexcept(connect(schedule(sch), receiver_t{nullptr})); struct *state-type* { Rcvr& *rcvr*; // *exposition only* variant_t *async-result*; // *exposition only* operation_t *op-state*; // *exposition only*explicit *state-type*(sched_t sch, Rcvr& rcvr) noexcept(nothrow): *rcvr*(rcvr), *op-state*(connect(schedule(sch), receiver_t{this})) {}}; return *state-type*{sch, rcvr};}

[ð](#lib:check-types,impls-for%3cschedule_from_t%3e)

`template<class Sndr, class... Env>
  static consteval void check-types();
`

[7](#exec.schedule.from-7)

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

*Effects*: Equivalent to:get_completion_signatures<schedule_result_t<*data-type*<Sndr>>, *FWD-ENV-T*(Env)...>();auto cs = get_completion_signatures<*child-type*<Sndr>, *FWD-ENV-T*(Env)...>();*decay-copyable-result-datums*(cs); // see [[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities")

[8](#exec.schedule.from-8)

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

Objects of the local class *state-type* can be used
to initialize a structured binding[.](#exec.schedule.from-8.sentence-1)

[9](#exec.schedule.from-9)

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

Let Sigs be
a pack of the arguments to the completion_signatures specialization
named by completion_signatures_of_t<*child-type*<Sndr>, *FWD-ENV-T*(env_of_t<Rcvr>)>[.](#exec.schedule.from-9.sentence-1)

Let *as-tuple* be an alias template such that*as-tuple*<Tag(Args...)> denotes
the type *decayed-tuple*<Tag, Args...>, and
let *is-nothrow-decay-copy-sig* be a variable template such thatauto(*is-nothrow-decay-copy-sig*<Tag(Args...  
)>) is
a constant expression of type bool and
equal to (is_nothrow_constructible_v<decay_t<Args>, Args> && ...)[.](#exec.schedule.from-9.sentence-2)

Let *error-completion* be a pack consisting of
the type set_error_t(exception_ptr) if (*is-nothrow-decay-copy-sig*<Sigs> &&...) is false,
and an empty pack otherwise[.](#exec.schedule.from-9.sentence-3)

Then variant_t denotes
the type variant<monostate, *as-tuple*<Sigs>..., *error-completion*...>,
except with duplicate types removed[.](#exec.schedule.from-9.sentence-4)

[10](#exec.schedule.from-10)

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

receiver_t is an alias for the following exposition-only class:namespace std::execution {struct *receiver-type* {using receiver_concept = receiver_t; *state-type** *state*; // *exposition only*void set_value() && noexcept { visit([this]<class Tuple>(Tuple& result) noexcept -> void {if constexpr (![same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")<monostate, Tuple>) {auto& [tag, ...args] = result;
 tag(std::move(*state*->*rcvr*), std::move(args)...); }}, *state*->*async-result*); }template<class Error>void set_error(Error&& err) && noexcept { execution::set_error(std::move(*state*->*rcvr*), std::forward<Error>(err)); }void set_stopped() && noexcept { execution::set_stopped(std::move(*state*->*rcvr*)); }decltype(auto) get_env() const noexcept {return *FWD-ENV*(execution::get_env(*state*->*rcvr*)); }};}

[11](#exec.schedule.from-11)

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

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[.](#exec.schedule.from-11.sentence-1)

[12](#exec.schedule.from-12)

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

The member *impls-for*<schedule_from_t>​::​*complete* is initialized with a callable object equivalent to the following lambda:[]<class Tag, class... Args>(auto, auto& state, auto& rcvr, Tag, Args&&... args) noexcept-> void {using result_t = *decayed-tuple*<Tag, Args...>; constexpr bool nothrow = (is_nothrow_constructible_v<decay_t<Args>, Args> && ...); try { state.*async-result*.template emplace<result_t>(Tag(), std::forward<Args>(args)...); } catch (...) {if constexpr (!nothrow) state.*async-result*.template emplace<tuple<set_error_t,
 exception_ptr>>(set_error, current_exception()); } start(state.*op-state*);};

[13](#exec.schedule.from-13)

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

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))[.](#exec.schedule.from-13.sentence-1)

Let out_rcvr be a subexpression denoting a receiver
that has an environment of type Env such that [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<OutSndr, Env> is true[.](#exec.schedule.from-13.sentence-2)

Let op be an lvalue referring to the operation state
that results from connecting out_sndr with out_rcvr[.](#exec.schedule.from-13.sentence-3)

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[.](#exec.schedule.from-13.sentence-4)

If scheduling onto sch fails,
an error completion on out_rcvr shall be executed
on an unspecified execution agent[.](#exec.schedule.from-13.sentence-5)

#### [33.9.12.8](#exec.on) execution​::​on [[exec.on]](exec.on)

[1](#exec.on-1)

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

The on sender adaptor has two forms:

- [(1.1)](#exec.on-1.1)

  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[.](#exec.on-1.1.sentence-1)

- [(1.2)](#exec.on-1.2)

  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[.](#exec.on-1.2.sentence-1)

[2](#exec.on-2)

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

The name on denotes a pipeable sender adaptor object[.](#exec.on-2.sentence-1)

For subexpressions sch and sndr,on(sch, sndr) is ill-formed if any of the following is true:

- [(2.1)](#exec.on-2.1)

decltype((sch)) does not satisfy [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]"), or

- [(2.2)](#exec.on-2.2)

decltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") andsndr is not
a pipeable sender adaptor closure object ([[exec.adapt.obj]](#obj "33.9.12.2 Closure objects")), or

- [(2.3)](#exec.on-2.3)

decltype((sndr)) satisfies [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") andsndr is also a pipeable sender adaptor closure object[.](#exec.on-2.sentence-2)

[3](#exec.on-3)

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

Otherwise, if decltype((sndr)) satisfies [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"),
the expression on(sch, sndr) is expression-equivalent to:transform_sender(*query-with-default*(get_domain, sch, default_domain()), *make-sender*(on, sch, sndr)) except that sch is evaluated only once[.](#exec.on-3.sentence-1)

[4](#exec.on-4)

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

For subexpressions sndr, sch, and closure, if

- [(4.1)](#exec.on-4.1)

decltype((sch)) does not satisfy [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]"), or

- [(4.2)](#exec.on-4.2)

decltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"), or

- [(4.3)](#exec.on-4.3)

closure is not a pipeable sender adaptor closure object ([[exec.adapt.obj]](#obj "33.9.12.2 Closure objects")),

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[.](#exec.on-4.sentence-1)

[5](#exec.on-5)

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

Let out_sndr and env be subexpressions,
let OutSndr be decltype((out_sndr)), and
let Env be decltype((env))[.](#exec.on-5.sentence-1)

If [*sender-for*](exec.snd.concepts#concept:sender-for "33.9.3 Sender concepts [exec.snd.concepts]")<OutSndr, on_t> is false,
then the expressions on.transform_env(out_sndr, env) andon.transform_sender(out_sndr, env) are ill-formed[.](#exec.on-5.sentence-2)

[6](#exec.on-6)

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

Otherwise:
Let *not-a-scheduler* be an unspecified empty class type[.](#exec.on-6.sentence-1)

[7](#exec.on-7)

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

The expression on.transform_env(out_sndr, env) has effects equivalent to:auto&& [_, data, _] = out_sndr;if constexpr ([scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")<decltype(data)>) {return *JOIN-ENV*(*SCHED-ENV*(std::forward_like<OutSndr>(data)), *FWD-ENV*(std::forward<Env>(env)));} else {return std::forward<Env>(env);}

[8](#exec.on-8)

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

The expression on.transform_sender(out_sndr, env) has effects equivalent to:auto&& [_, data, child] = out_sndr;if constexpr ([scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")<decltype(data)>) {auto orig_sch =*query-with-default*(get_scheduler, env, *not-a-scheduler*()); if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")<decltype(orig_sch), *not-a-scheduler*>) {return *not-a-sender*{}; } else {return continues_on( starts_on(std::forward_like<OutSndr>(data), std::forward_like<OutSndr>(child)),
 std::move(orig_sch)); }} else {auto& [sch, closure] = data; auto orig_sch = *query-with-default*( get_completion_scheduler<set_value_t>,
 get_env(child), *query-with-default*(get_scheduler, env, *not-a-scheduler*())); if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")<decltype(orig_sch), *not-a-scheduler*>) {return *not-a-sender*{}; } else {return write_env( continues_on( std::forward_like<OutSndr>(closure)( continues_on( write_env(std::forward_like<OutSndr>(child), *SCHED-ENV*(orig_sch)),
 sch)),
 orig_sch), *SCHED-ENV*(sch)); }}

[9](#exec.on-9)

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

Let out_sndr be a subexpression denoting
a sender returned from on(sch, sndr) or one equal to such, and
let OutSndr be the type decltype((out_sndr))[.](#exec.on-9.sentence-1)

Let out_rcvr be a subexpression denoting a receiver
that has an environment of type Env such that [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<OutSndr, Env> is true[.](#exec.on-9.sentence-2)

Let op be an lvalue referring to the operation state
that results from connecting out_sndr with out_rcvr[.](#exec.on-9.sentence-3)

Calling start(op) shall

- [(9.1)](#exec.on-9.1)

remember the current scheduler, get_scheduler(get_env(rcvr));

- [(9.2)](#exec.on-9.2)

start sndr on an execution agent belonging tosch's associated execution resource;

- [(9.3)](#exec.on-9.3)

upon sndr's completion,
transfer execution back to the execution resource
associated with the scheduler remembered in step 1; and

- [(9.4)](#exec.on-9.4)

forward sndr's async result to out_rcvr[.](#exec.on-9.sentence-4)

If any scheduling operation fails,
an error completion on out_rcvr shall be executed
on an unspecified execution agent[.](#exec.on-9.sentence-5)

[10](#exec.on-10)

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

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))[.](#exec.on-10.sentence-1)

Let out_rcvr be a subexpression denoting a receiver
that has an environment of type Env such that [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<OutSndr, Env> is true[.](#exec.on-10.sentence-2)

Let op be an lvalue referring to the operation state
that results from connecting out_sndr with out_rcvr[.](#exec.on-10.sentence-3)

Calling start(op) shall

- [(10.1)](#exec.on-10.1)

remember the current scheduler,
which is the first of the following expressions that is well-formed:
  * [(10.1.1)](#exec.on-10.1.1)

get_completion_scheduler<set_value_t>(get_env(sndr))

  * [(10.1.2)](#exec.on-10.1.2)

get_scheduler(get_env(rcvr));

- [(10.2)](#exec.on-10.2)

start sndr on the current execution agent;

- [(10.3)](#exec.on-10.3)

upon sndr's completion,
transfer execution to an agent
owned by sch's associated execution resource;

- [(10.4)](#exec.on-10.4)

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

- [(10.5)](#exec.on-10.5)

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[.](#exec.on-10.sentence-4)

If any scheduling operation fails,
an error completion on out_rcvr shall be executed on
an unspecified execution agent[.](#exec.on-10.sentence-5)

#### [33.9.12.9](#exec.then) execution​::​then, execution​::​upon_error, execution​::​upon_stopped [[exec.then]](exec.then)

[1](#exec.then-1)

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

then attaches an invocable as a continuation
for an input sender's value completion operation[.](#exec.then-1.sentence-1)

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[.](#exec.then-1.sentence-2)

[2](#exec.then-2)

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

The names then, upon_error, and upon_stopped denote pipeable sender adaptor objects[.](#exec.then-2.sentence-1)

Let the expression *then-cpo* be one ofthen, upon_error, or upon_stopped[.](#exec.then-2.sentence-2)

For subexpressions sndr and f,
if decltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"), ordecltype((f)) does not satisfy [*movable-value*](exec.general#concept:movable-value "33.1 General [exec.general]"),*then-cpo*(sndr, f) is ill-formed[.](#exec.then-2.sentence-3)

[3](#exec.then-3)

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

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[.](#exec.then-3.sentence-1)

[4](#exec.then-4)

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

For then, upon_error, and upon_stopped,
let *set-cpo* beset_value, set_error, and set_stopped, respectively[.](#exec.then-4.sentence-1)

The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
is specialized for *then-cpo* as follows:

[ð](#lib:impls-for%3cdecayed-typeof%3cthen-cpo%3e%3e)

namespace std::execution {template<>struct *impls-for*<*decayed-typeof*<*then-cpo*>> : *default-impls* {static constexpr auto *complete* =[]<class Tag, class... Args>(auto, auto& fn, auto& rcvr, Tag, Args&&... args) noexcept -> void {if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")<Tag, *decayed-typeof*<set-cpo>>) {*TRY-SET-VALUE*(rcvr,
 invoke(std::move(fn), std::forward<Args>(args)...)); } else { Tag()(std::move(rcvr), std::forward<Args>(args)...); }}; template<class Sndr, class... Env>static consteval void *check-types*(); };}

[ð](#lib:check-types,impls-for%3cdecayed-typeof%3cthen-cpo%3e%3e)

`template<class Sndr, class... Env>
  static consteval void check-types();
`

[5](#exec.then-5)

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

*Effects*: Equivalent to:auto cs = get_completion_signatures<*child-type*<Sndr>, *FWD-ENV-T*(Env)...>();auto fn = []<class... Ts>(set_value_t(*)(Ts...)) {if constexpr (![invocable](concept.invocable#concept:invocable "18.7.2 Concept invocable [concept.invocable]")<remove_cvref_t<*data-type*<Sndr>>, Ts...>)throw *unspecified-exception*();};
cs.*for-each*(*overload-set*{fn, [](auto){}}); where *unspecified-exception* is
a type derived from exception[.](#exec.then-5.sentence-1)

[6](#exec.then-6)

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

The expression *then-cpo*(sndr, f) has undefined behavior
unless it returns a sender out_sndr that

- [(6.1)](#exec.then-6.1)

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

- [(6.2)](#exec.then-6.2)

forwards all other completion operations unchanged[.](#exec.then-6.sentence-1)

#### [33.9.12.10](#exec.let) execution​::​let_value, execution​::​let_error, execution​::​let_stopped [[exec.let]](exec.let)

[1](#exec.let-1)

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

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[.](#exec.let-1.sentence-1)

[2](#exec.let-2)

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

For let_value, let_error, and let_stopped,
let *set-cpo* beset_value, set_error, and set_stopped, respectively[.](#exec.let-2.sentence-1)

Let the expression *let-cpo* be one oflet_value, let_error, or let_stopped[.](#exec.let-2.sentence-2)

For a subexpression sndr,
let *let-env*(sndr) be expression-equivalent to
the first well-formed expression below:

- [(2.1)](#exec.let-2.1)

*SCHED-ENV*(get_completion_scheduler<*decayed-typeof*<*set-cpo*>>(get_env(sndr)))

- [(2.2)](#exec.let-2.2)

*MAKE-ENV*(get_domain, get_domain(get_env(sndr)))

- [(2.3)](#exec.let-2.3)

(void(sndr), env<>{})

[3](#exec.let-3)

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

The names let_value, let_error, and let_stopped denote
pipeable sender adaptor objects[.](#exec.let-3.sentence-1)

For subexpressions sndr and f,
let F be the decayed type of f[.](#exec.let-3.sentence-2)

If decltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") or
if decltype((f)) does not satisfy [*movable-value*](exec.general#concept:movable-value "33.1 General [exec.general]"),
the expression *let-cpo*(sndr, f) is ill-formed[.](#exec.let-3.sentence-3)

If F does not satisfy [invocable](concept.invocable#concept:invocable "18.7.2 Concept invocable [concept.invocable]"),
the expression let_stopped(sndr, f) is ill-formed[.](#exec.let-3.sentence-4)

[4](#exec.let-4)

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

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[.](#exec.let-4.sentence-1)

[5](#exec.let-5)

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

The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
is specialized for *let-cpo* as follows:

[ð](#lib:impls-for%3cdecayed-typeof%3clet-cpo%3e%3e)

namespace std::execution {template<class State, class Rcvr, class... Args>void *let-bind*(State& state, Rcvr& rcvr, Args&&... args); // *exposition only*template<>struct *impls-for*<*decayed-typeof*<*let-cpo*>> : *default-impls* {static constexpr auto *get-state* = *see below*; static constexpr auto *complete* = *see below*; template<class Sndr, class... Env>static consteval void *check-types*(); };}

[6](#exec.let-6)

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

Let *receiver2* denote the following exposition-only class template:namespace std::execution {template<class Rcvr, class Env>struct *receiver2* {using receiver_concept = receiver_t; template<class... Args>void set_value(Args&&... args) && noexcept { execution::set_value(std::move(*rcvr*), std::forward<Args>(args)...); }template<class Error>void set_error(Error&& err) && noexcept { execution::set_error(std::move(*rcvr*), std::forward<Error>(err)); }void set_stopped() && noexcept { execution::set_stopped(std::move(*rcvr*)); }decltype(auto) get_env() const noexcept {return *see below*; } Rcvr& *rcvr*; // *exposition only* Env *env*; // *exposition only*};}

Invocation of the function *receiver2*​::​get_env returns an object e such that

- [(6.1)](#exec.let-6.1)

decltype(e) models [*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") and

- [(6.2)](#exec.let-6.2)

given a query object q,
the expression e.query(q) is expression-equivalent
to *env*.query(q) if that expression is valid;
otherwise,
if the type of q satisfies [*forwarding-query*](execution.syn#concept:forwarding-query "33.4 Header <execution> synopsis [execution.syn]"),e.query(q) is expression-equivalent
to get_env(*rcvr*).query(q);
otherwise,e.query(q) is ill-formed[.](#exec.let-6.sentence-2)

[ð](#lib:check-types,impls-for%3cdecayed-typeof%3clet-cpo%3e%3e)

`template<class Sndr, class... Env>
  static consteval void check-types();
`

[7](#exec.let-7)

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

*Effects*: Equivalent to:using LetFn = remove_cvref_t<*data-type*<Sndr>>;auto cs = get_completion_signatures<*child-type*<Sndr>, *FWD-ENV-T*(Env)...>();auto fn = []<class... Ts>(*decayed-typeof*<*set-cpo*>(*)(Ts...)) {if constexpr (!*is-valid-let-sender*) // *see below*throw *unspecified-exception*();};
cs.*for-each*(*overload-set*(fn, [](auto){})); where *unspecified-exception* is
a type derived from exception, and
where *is-valid-let-sender* is true if and only if
all of the following are true:

- [(7.1)](#exec.let-7.1)

([constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept constructible_­from [concept.constructible]")<decay_t<Ts>, Ts> &&...)

- [(7.2)](#exec.let-7.2)

[invocable](concept.invocable#concept:invocable "18.7.2 Concept invocable [concept.invocable]")<LetFn, decay_t<Ts>&...>

- [(7.3)](#exec.let-7.3)

[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")<invoke_result_t<LetFn, decay_t<Ts>&...>>

- [(7.4)](#exec.let-7.4)

sizeof...(Env) == 0 || [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<invoke_result_t<LetFn, decay_t<Ts>&...>, *env-t*  
...>

where *env-t* is the packdecltype(*let-cpo*.transform_env(declval<Sndr>(), declval<Env>()))[.](#exec.let-7.sentence-1)

[8](#exec.let-8)

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

*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) requires *see 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*; struct *state-type* { fn_t *fn*; // *exposition only* env_t *env*; // *exposition only* args_variant_t *args*; // *exposition only* ops2_variant_t *ops2*; // *exposition only*}; return *state-type*{*allocator-aware-forward*(std::forward_like<Sndr>(fn), rcvr), *let-env*(child), {}, {}};}

[9](#exec.let-9)

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

Let Sigs be a pack of the arguments
to the completion_signatures specialization named bycompletion_signatures_of_t<*child-type*<Sndr>, *FWD-ENV-T*(env_of_t<Rcvr>)>[.](#exec.let-9.sentence-1)

Let LetSigs be a pack of those types in Sigs with a return type of *decayed-typeof*<*set-cpo*>[.](#exec.let-9.sentence-2)

Let *as-tuple* be an alias template
such that *as-tuple*<Tag(Args...)> denotes
the type *decayed-tuple*<Args...>[.](#exec.let-9.sentence-3)

Then args_variant_t denotes
the type variant<monostate, *as-tuple*<LetSigs>...> except with duplicate types removed[.](#exec.let-9.sentence-4)

[10](#exec.let-10)

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

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*<F, decay_t<Args>&...>[.](#exec.let-10.sentence-1)

Then ops2_variant_t denotes
the typevariant<monostate, connect_result_t<*as-sndr2*<LetSigs>, *receiver2*<Rcvr, env_t>>...> except with duplicate types removed[.](#exec.let-10.sentence-2)

[11](#exec.let-11)

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

The [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") constraining the above lambda is satisfied
if and only if
the types args_variant_t and ops2_variant_t are well-formed[.](#exec.let-11.sentence-1)

[12](#exec.let-12)

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

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}));

[13](#exec.let-13)

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

*impls-for*<*decayed-typeof*<let-cpo>>​::​*complete* is initialized with a callable object equivalent to the following:[]<class Tag, class... Args>(auto, auto& state, auto& rcvr, Tag, Args&&... args) noexcept -> void {if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")<Tag, *decayed-typeof*<*set-cpo*>>) {*TRY-EVAL*(rcvr, *let-bind*(state, rcvr, std::forward<Args>(args)...)); } else { Tag()(std::move(rcvr), std::forward<Args>(args)...); }}

[14](#exec.let-14)

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

Let sndr and env be subexpressions, and
let Sndr be decltype((sndr))[.](#exec.let-14.sentence-1)

If[*sender-for*](exec.snd.concepts#concept:sender-for "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, *decayed-typeof*<*let-cpo*>> is false,
then the expression *let-cpo*.transform_env(sndr, env) is ill-formed[.](#exec.let-14.sentence-2)

Otherwise, it is equal to:auto& [_, _, child] = sndr;return *JOIN-ENV*(*let-env*(child), *FWD-ENV*(env));

[15](#exec.let-15)

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

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[.](#exec.let-15.sentence-1)

The expression connect(out_sndr, rcvr) has undefined behavior
unless it creates an asynchronous operation ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations")) that,
when started:

- [(15.1)](#exec.let-15.1)

invokes f when *set-cpo* is called
with sndr's result datums,

- [(15.2)](#exec.let-15.2)

makes its completion dependent on
the completion of a sender returned by f, and

- [(15.3)](#exec.let-15.3)

propagates the other completion operations sent by sndr[.](#exec.let-15.sentence-2)

#### [33.9.12.11](#exec.bulk) execution​::​bulk, execution​::​bulk_chunked, and execution​::​bulk_unchunked [[exec.bulk]](exec.bulk)

[1](#exec.bulk-1)

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

bulk, bulk_chunked, and bulk_unchunked run a task repeatedly for every index in an index space[.](#exec.bulk-1.sentence-1)

[2](#exec.bulk-2)

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

The names bulk, bulk_chunked, and bulk_unchunked denote pipeable sender adaptor objects[.](#exec.bulk-2.sentence-1)

Let *bulk-algo* be eitherbulk, bulk_chunked, or bulk_unchunked[.](#exec.bulk-2.sentence-2)

For subexpressions sndr, policy, shape, and f,
letPolicy be remove_cvref_t<decltype(policy)>,Shape be decltype(auto(shape)), andFunc be decay_t<decltype((f))>[.](#exec.bulk-2.sentence-3)

If

- [(2.1)](#exec.bulk-2.1)

decltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"), or

- [(2.2)](#exec.bulk-2.2)

is_execution_policy_v<Policy> is false, or

- [(2.3)](#exec.bulk-2.3)

Shape does not satisfy [integral](concepts.arithmetic#concept:integral "18.4.7 Arithmetic concepts [concepts.arithmetic]"), or

- [(2.4)](#exec.bulk-2.4)

Func does not model [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14 Concept copy_­constructible [concept.copyconstructible]"),

*bulk-algo*(sndr, policy, shape, f) is ill-formed[.](#exec.bulk-2.sentence-4)

[3](#exec.bulk-3)

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

Otherwise,
the expression *bulk-algo*(sndr, policy, shape, f) is expression-equivalent to:

transform_sender(*get-domain-early*(sndr), *make-sender*(*bulk-algo*, *product-type*<*see below*, Shape, Func>{policy, shape, f}, sndr)) except that sndr is evaluated only once[.](#exec.bulk-3.sentence-2)

The first template argument of *product-type* is Policy if Policy models [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14 Concept copy_­constructible [concept.copyconstructible]"), andconst Policy& otherwise[.](#exec.bulk-3.sentence-3)

[4](#exec.bulk-4)

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

Let sndr and env be subexpressions such thatSndr is decltype((sndr))[.](#exec.bulk-4.sentence-1)

If [*sender-for*](exec.snd.concepts#concept:sender-for "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, bulk_t> is false, then
the expression bulk.transform_sender(sndr, env) is ill-formed;
otherwise, it is equivalent to:auto [_, data, child] = sndr;auto& [policy, shape, f] = data;auto new_f = [func = std::move(f)](Shape begin, Shape end, auto&&... vs)noexcept(noexcept(f(begin, vs...))) {while (begin != end) func(begin++, vs...);}return bulk_chunked(std::move(child), policy, shape, std::move(new_f));

[*Note [1](#exec.bulk-note-1)*:

This causes the bulk(sndr, policy, shape, f) sender to be
expressed in terms of bulk_chunked(sndr, policy, shape, f) when
it is connected to a receiver whose
execution domain does not customize bulk[.](#exec.bulk-4.sentence-2)

â *end note*]

[5](#exec.bulk-5)

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

The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
is specialized for bulk_chunked_t as follows:

[ð](#lib:impls-for%3cbulk_chunked_t%3e)

namespace std::execution {template<>struct *impls-for*<bulk_chunked_t> : *default-impls* {static constexpr auto *complete* = *see below*; template<class Sndr, class... Env>static consteval void *check-types*(); };}

The member *impls-for*<bulk_chunked_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-> void requires *see below* {if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")<Tag, set_value_t>) {auto& [policy, shape, f] = state; constexpr bool nothrow = noexcept(f(auto(shape), auto(shape), args...)); *TRY-EVAL*(rcvr, [&]() noexcept(nothrow) { f(static_cast<decltype(auto(shape))>(0), auto(shape), args...);
 Tag()(std::move(rcvr), std::forward<Args>(args)...); }()); } else { Tag()(std::move(rcvr), std::forward<Args>(args)...); }}

The expression in the [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") of the lambda above istrue if and only
if Tag denotes a type other than set_value_t or
if the expression f(auto(shape), auto(shape), args...) is well-formed[.](#exec.bulk-5.sentence-3)

[6](#exec.bulk-6)

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

The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
is specialized for bulk_unchunked_t as follows:namespace std::execution {template<>struct *impls-for*<bulk_unchunked_t> : *default-impls* {static constexpr auto *complete* = *see below*; };}

The member *impls-for*<bulk_unchunked_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-> void requires *see below* {if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")<Tag, set_value_t>) {auto& [shape, f] = state; constexpr bool 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*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") 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[.](#exec.bulk-6.sentence-3)

[ð](#lib:check-types,impls-for%3cbulk_t%3e)

`template<class Sndr, class... Env>
  static consteval void check-types();
`

[7](#exec.bulk-7)

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

*Effects*: Equivalent to:auto cs = get_completion_signatures<*child-type*<Sndr>, *FWD-ENV-T*(Env)...>();auto fn = []<class... Ts>(set_value_t(*)(Ts...)) {if constexpr (![invocable](concept.invocable#concept:invocable "18.7.2 Concept invocable [concept.invocable]")<remove_cvref_t<*data-type*<Sndr>>, Ts&...>)throw *unspecified-exception*();};
cs.*for-each*(*overload-set*(fn, [](auto){})); where *unspecified-exception* is
a type derived from exception[.](#exec.bulk-7.sentence-1)

[8](#exec.bulk-8)

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

Let the subexpression out_sndr denote
the result of the invocation*bulk-algo*(sndr, policy, 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[.](#exec.bulk-8.sentence-1)

The expression connect(out_sndr, rcvr) has undefined behavior
unless it creates an asynchronous operation ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations")) that,
when started:

- [(8.1)](#exec.bulk-8.1)

  If sndr has a successful completion, whereargs is a pack of lvalue subexpressions
referring to the value completion result datums of sndr, or
decayed copies of those values if they model [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14 Concept copy_­constructible [concept.copyconstructible]"),
then:

  * [(8.1.1)](#exec.bulk-8.1.1)

      If out_sndr also completes successfully, then:

    +
          [(8.1.1.1)](#exec.bulk-8.1.1.1)
          for bulk,
 invokes f(i, args...) for every i of type Shape from 0 to shape;

    +
          [(8.1.1.2)](#exec.bulk-8.1.1.2)
          for bulk_unchunked,
 invokes f(i, args...) for every i of type Shape from 0 to shape;
          *Recommended practice*: The underlying scheduler should execute each iteration
 on a distinct execution agent[.](#exec.bulk-8.1.1.2.sentence-2)

    +
          [(8.1.1.3)](#exec.bulk-8.1.1.3)
          for bulk_chunked,
 invokes f(b, e, args...) zero or more times
 with pairs of b and e of type Shape in range [0, shape],
 such that b<e and
 for every i of type Shape from 0 to shape,
 there is exactly one invocation with a pair b and e,
 such that i is in the range [b, e)[.](#exec.bulk-8.1.1.3.sentence-1)

  * [(8.1.2)](#exec.bulk-8.1.2)

      If out_sndr completes with set_error(rcvr, eptr), then
 the asynchronous operation may invoke a subset of
 the invocations of f before the error completion handler is called, and eptr is an exception_ptr containing either:
    +
          [(8.1.2.1)](#exec.bulk-8.1.2.1)
an exception thrown by an invocation of f, or

    +
          [(8.1.2.2)](#exec.bulk-8.1.2.2)
a bad_alloc exception if
 the implementation fails to allocate required resources, or

    +
          [(8.1.2.3)](#exec.bulk-8.1.2.3)
an exception derived from runtime_error[.](#exec.bulk-8.1.2.sentence-1)

  * [(8.1.3)](#exec.bulk-8.1.3)

      If out_sndr completes with set_stopped(rcvr), then
 the asynchronous operation may invoke a subset of
 the invocations of f before the stopped completion handler[.](#exec.bulk-8.1.3.sentence-1)

- [(8.2)](#exec.bulk-8.2)

  If sndr does not complete with set_value, then
the completion is forwarded to recv[.](#exec.bulk-8.2.sentence-1)

- [(8.3)](#exec.bulk-8.3)

  For *bulk-algo*,
the parameter policy describes
the manner in which
the execution of the asynchronous operations corresponding to these algorithms
may be parallelized and
the manner in which
they apply f[.](#exec.bulk-8.3.sentence-1)
  Permissions and requirements
on parallel algorithm element access functions ([[algorithms.parallel.exec]](algorithms.parallel.exec "26.3.3 Effect of execution policies on algorithm execution"))
apply to f[.](#exec.bulk-8.3.sentence-2)

[9](#exec.bulk-9)

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

[*Note [2](#exec.bulk-note-2)*:

The asynchronous operation corresponding to*bulk-algo*(sndr, policy, shape, f) can complete with set_stopped if cancellation is requested or
ignore cancellation requests[.](#exec.bulk-9.sentence-1)

â *end note*]

#### [33.9.12.12](#exec.when.all) execution​::​when_all [[exec.when.all]](exec.when.all)

[1](#exec.when.all-1)

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

when_all and when_all_with_variant both adapt multiple input senders into a sender
that completes when all input senders have completed[.](#exec.when.all-1.sentence-1)

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[.](#exec.when.all-1.sentence-2)

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](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")[.](#exec.when.all-1.sentence-3)

[2](#exec.when.all-2)

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

The names when_all and when_all_with_variant denote
customization point objects[.](#exec.when.all-2.sentence-1)

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))...>[.](#exec.when.all-2.sentence-2)

Let CD2 be CD if CD is well-formed, anddefault_domain otherwise[.](#exec.when.all-2.sentence-3)

The expressions when_all(sndrs...) andwhen_all_with_variant(sndrs...) are ill-formed
if any of the following is true:

- [(2.1)](#exec.when.all-2.1)

sizeof...(sndrs) is 0, or

- [(2.2)](#exec.when.all-2.2)

([sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")<Sndrs> && ...) is false[.](#exec.when.all-2.sentence-4)

[3](#exec.when.all-3)

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

The expression when_all(sndrs...) is expression-equivalent to:transform_sender(CD2(), *make-sender*(when_all, {}, sndrs...))

[4](#exec.when.all-4)

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

The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
is specialized for when_all_t as follows:

[ð](#lib:impls-for%3cwhen_all_t%3e)

namespace std::execution {template<>struct *impls-for*<when_all_t> : *default-impls* {static constexpr auto *get-attrs* = *see below*; static constexpr auto *get-env* = *see below*; static constexpr auto *get-state* = *see below*; static constexpr auto *start* = *see below*; static constexpr auto *complete* = *see below*; template<class Sndr, class... Env>static consteval void *check-types*(); };}

[5](#exec.when.all-5)

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

Let *make-when-all-env* be
the following exposition-only function template:template<class Env>constexpr auto *make-when-all-env*(inplace_stop_source& stop_src, // *exposition only* Env&& env) noexcept {return *see below*;}

Returns an object e such that

- [(5.1)](#exec.when.all-5.1)

decltype(e) models [*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]"), and

- [(5.2)](#exec.when.all-5.2)

e.query(get_stop_token) is expression-equivalent tostate.*stop-src*.get_token(), and

- [(5.3)](#exec.when.all-5.3)

given a query object q with type other than cv stop_token_t and
whose type satisfies *forwarding-query*,e.query(q) is expression-equivalent to get_env(rcvr).query(q)[.](#exec.when.all-5.sentence-2)

[6](#exec.when.all-6)

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

Let *when-all-env* be an alias template such that*when-all-env*<Env> denotes the typedecltype(*make-  
when-all-env*(declval<inplace_stop_source&>(), declval<Env>()))[.](#exec.when.all-6.sentence-1)

[ð](#lib:check-types,impls-for%3cwhen_all_t%3e)

`template<class Sndr, class... Env>
  static consteval void check-types();
`

[7](#exec.when.all-7)

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

Let Is be the pack of integral template arguments of
the integer_sequence specialization denoted by*indices-for*<Sndr>[.](#exec.when.all-7.sentence-1)

[8](#exec.when.all-8)

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

*Effects*: Equivalent to:auto fn = []<class Child>() {auto cs = get_completion_signatures<Child, *when-all-env*<Env>...>(); if constexpr (cs.*count-of*(set_value) >= 2)throw *unspecified-exception*(); *decay-copyable-result-datums*(cs); // see [[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities")};(fn.template operator()<*child-type*<Sndr, Is>>(), ...); where *unspecified-exception* is
a type derived from exception[.](#exec.when.all-8.sentence-1)

[9](#exec.when.all-9)

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

*Throws*: Any exception thrown as a result of evaluating the *Effects*, or
an exception of an unspecified type
derived from exception when CD is ill-formed[.](#exec.when.all-9.sentence-1)

[10](#exec.when.all-10)

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

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 {if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")<CD, default_domain>) {return env<>(); } else {return *MAKE-ENV*(get_domain, CD()); }}

[11](#exec.when.all-11)

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

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 {return *make-when-all-env*(state.*stop-src*, get_env(rcvr));}

[12](#exec.when.all-12)

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

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(noexcept(e)) -> decltype(e) {return e;} where e is the expressionstd::forward<Sndr>(sndr).*apply*(*make-state*<Rcvr>()) and where *make-state* is the following exposition-only class template:enum class *disposition* { *started*, *error*, *stopped* }; // *exposition only*template<class Rcvr>struct *make-state* {template<class... Sndrs>auto operator()(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*>; struct *state-type* {void *arrive*(Rcvr& rcvr) noexcept { // *exposition only*if (0 == --count) {*complete*(rcvr); }}void *complete*(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*}; return *state-type*{}; }};

[13](#exec.when.all-13)

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

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[.](#exec.when.all-13.sentence-1)

[14](#exec.when.all-14)

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

The alias values_tuple denotes the typetuple<value_types_of_t<Sndrs, *FWD-ENV-T*(env_of_t<Rcvr>), *decayed-tuple*, optional>...> if that type is well-formed; otherwise, tuple<>[.](#exec.when.all-14.sentence-1)

[15](#exec.when.all-15)

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

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[.](#exec.when.all-15.sentence-1)

[16](#exec.when.all-16)

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

The membervoid *state-type*​::​*complete*(Rcvr& rcvr) noexcept behaves as follows:

- [(16.1)](#exec.when.all-16.1)

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);

- [(16.2)](#exec.when.all-16.2)

Otherwise,
if disp is equal to *disposition*​::​*error*,
evaluates:*on_stop*.reset();
visit([&]<class Error>(Error& error) noexcept {if constexpr (![same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")<Error, *none-such*>) { set_error(std::move(rcvr), std::move(error)); }},
 errors);

- [(16.3)](#exec.when.all-16.3)

Otherwise, evaluates:*on_stop*.reset();
set_stopped(std::move(rcvr));

[17](#exec.when.all-17)

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

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), ...); }}

[18](#exec.when.all-18)

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

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>(this auto& complete, Index, State& state, Rcvr& rcvr, Set, Args&&... args) noexcept -> void {if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")<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)...); }} else if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")<Set, set_stopped_t>) {auto expected = *disposition*::*started*; if (state.disp.compare_exchange_strong(expected, *disposition*::*stopped*)) { state.*stop_src*.request_stop(); }} else if constexpr (![same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")<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...)[.](#exec.when.all-18.sentence-1)

[19](#exec.when.all-19)

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

The expression when_all_with_variant(sndrs...) is expression-equivalent to:transform_sender(CD2(), *make-sender*(when_all_with_variant, {}, sndrs...));

[20](#exec.when.all-20)

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

Given subexpressions sndr and env,
if[*sender-for*](exec.snd.concepts#concept:sender-for "33.9.3 Sender concepts [exec.snd.concepts]")<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))...);

[*Note [1](#exec.when.all-note-1)*:

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[.](#exec.when.all-20.sentence-1)

â *end note*]

#### [33.9.12.13](#exec.into.variant) execution​::​into_variant [[exec.into.variant]](exec.into.variant)

[1](#exec.into.variant-1)

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

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[.](#exec.into.variant-1.sentence-1)

[2](#exec.into.variant-2)

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

The name into_variant denotes a pipeable sender adaptor object[.](#exec.into.variant-2.sentence-1)

For a subexpression sndr, let Sndr be decltype((sndr))[.](#exec.into.variant-2.sentence-2)

If Sndr does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"),into_variant(sndr) is ill-formed[.](#exec.into.variant-2.sentence-3)

[3](#exec.into.variant-3)

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

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[.](#exec.into.variant-3.sentence-1)

[4](#exec.into.variant-4)

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

The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
is specialized for into_variant as follows:

[ð](#lib:impls-for%3cinto_variant_t%3e)

namespace std::execution {template<>struct *impls-for*<into_variant_t> : *default-impls* {static constexpr auto *get-state* = *see below*; static constexpr auto *complete* = *see below*; template<class Sndr, class... Env>static consteval void *check-types*() {auto cs = get_completion_signatures<*child-type*<Sndr>, *FWD-ENV-T*(Env)...>(); *decay-copyable-result-datums*(cs); // see [[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities")}};}

[5](#exec.into.variant-5)

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

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>, *FWD-ENV-T*(env_of_t<Rcvr>)>> {return {};}

[6](#exec.into.variant-6)

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

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 {if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")<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)...); }}

#### [33.9.12.14](#exec.stopped.opt) execution​::​stopped_as_optional [[exec.stopped.opt]](exec.stopped.opt)

[1](#exec.stopped.opt-1)

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

stopped_as_optional maps a sender's stopped completion operation
into a value completion operation as a disengaged optional[.](#exec.stopped.opt-1.sentence-1)

The sender's value completion operation
is also converted into an optional[.](#exec.stopped.opt-1.sentence-2)

The result is a sender that never completes with stopped,
reporting cancellation by completing with a disengaged optional[.](#exec.stopped.opt-1.sentence-3)

[2](#exec.stopped.opt-2)

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

The name stopped_as_optional denotes a pipeable sender adaptor object[.](#exec.stopped.opt-2.sentence-1)

For a subexpression sndr, let Sndr be decltype((sndr))[.](#exec.stopped.opt-2.sentence-2)

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[.](#exec.stopped.opt-2.sentence-3)

[3](#exec.stopped.opt-3)

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

The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
is specialized for stopped_as_optional_t as follows:

[ð](#lib:impls-for%3cstopped_as_optional_t%3e)

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](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")<void, *single-sender-value-type*<*child-type*<Sndr>, *FWD-ENV-T*(Env)...>>); })throw *unspecified-exception*(); }};} where *unspecified-exception* is
a type derived from exception[.](#exec.stopped.opt-3.sentence-1)

[4](#exec.stopped.opt-4)

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

Let sndr and env be subexpressions
such that Sndr is decltype((sndr)) andEnv is decltype((env))[.](#exec.stopped.opt-4.sentence-1)

If [*sender-for*](exec.snd.concepts#concept:sender-for "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, stopped_as_optional_t> is false then the expression stopped_as_optional.transform_sender(sndr, env) is ill-formed;
otherwise,
if [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<*child-type*<Sndr>, *FWD-ENV-T*(Env)> is false,
the expression stopped_as_optional.transform_sender(sndr, env) is equivalent to *not-a-sender*();
otherwise, it is equivalent to: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>()); });

#### [33.9.12.15](#exec.stopped.err) execution​::​stopped_as_error [[exec.stopped.err]](exec.stopped.err)

[1](#exec.stopped.err-1)

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

stopped_as_error maps an input sender's stopped completion operation
into an error completion operation as a custom error type[.](#exec.stopped.err-1.sentence-1)

The result is a sender that never completes with stopped,
reporting cancellation by completing with an error[.](#exec.stopped.err-1.sentence-2)

[2](#exec.stopped.err-2)

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

The name stopped_as_error denotes a pipeable sender adaptor object[.](#exec.stopped.err-2.sentence-1)

For some subexpressions sndr and err,
let Sndr be decltype((sndr)) and
let Err be decltype((err))[.](#exec.stopped.err-2.sentence-2)

If the type Sndr does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") or
if the type Err does not satisfy [*movable-value*](exec.general#concept:movable-value "33.1 General [exec.general]"),stopped_as_error(sndr, err) is ill-formed[.](#exec.stopped.err-2.sentence-3)

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[.](#exec.stopped.err-2.sentence-4)

[3](#exec.stopped.err-3)

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

Let sndr and env be subexpressions
such that Sndr is decltype((sndr)) andEnv is decltype((env))[.](#exec.stopped.err-3.sentence-1)

If [*sender-for*](exec.snd.concepts#concept:sender-for "33.9.3 Sender concepts [exec.snd.concepts]")<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)]() mutable noexcept(is_nothrow_move_constructible_v<E>) {return just_error(std::move(err)); });

#### [33.9.12.16](#exec.associate) execution​::​associate [[exec.associate]](exec.associate)

[1](#exec.associate-1)

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

associate tries to associate
a sender with an async scope such that
the scope can track the lifetime of any asynchronous operations
created with the sender[.](#exec.associate-1.sentence-1)

[2](#exec.associate-2)

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

Let *associate-data* be the following exposition-only class template:

[ð](#lib:execution::associate-data)

namespace std::execution {template<[scope_token](exec.scope.concepts#concept:scope_token "33.14.1 Execution scope concepts [exec.scope.concepts]") Token, [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender>struct *associate-data* { // *exposition only*using *wrap-sender* = // *exposition only* remove_cvref_t<decltype(declval<Token&>().wrap(declval<Sender>()))>; explicit *associate-data*(Token t, Sender&& s): *sndr*(t.wrap(std::forward<Sender>(s))), *token*(t) {if (!*token*.try_associate())*sndr*.reset(); }*associate-data*(const *associate-data*& other)noexcept(is_nothrow_copy_constructible_v<*wrap-sender*> &&noexcept(other.*token*.try_associate())); *associate-data*(*associate-data*&& other)noexcept(is_nothrow_move_constructible_v<*wrap-sender*>); ~*associate-data*();

 optional<pair<Token, *wrap-sender*>> release() && noexcept(is_nothrow_move_constructible_v<*wrap-sender*>); private: optional<*wrap-sender*> *sndr*; // *exposition only* Token *token*; // *exposition only*}; template<[scope_token](exec.scope.concepts#concept:scope_token "33.14.1 Execution scope concepts [exec.scope.concepts]") Token, [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender>*associate-data*(Token, Sender&&) -> *associate-data*<Token, Sender>;}

[3](#exec.associate-3)

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

For an *associate-data* object a,a.*sndr*.has_value() is true if and only if
an association was successfully made and is owned by a[.](#exec.associate-3.sentence-1)

[ð](#lib:execution::associate-data,constructor)

`associate-data(const associate-data& other)
  noexcept(is_nothrow_copy_constructible_v<wrap-sender> &&
           noexcept(other.token.try_associate()));
`

[4](#exec.associate-4)

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

*Constraints*: [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14 Concept copy_­constructible [concept.copyconstructible]")<*wrap-sender*> is true[.](#exec.associate-4.sentence-1)

[5](#exec.associate-5)

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

*Effects*: Value-initializes *sndr* and
initializes *token* with other.*token*[.](#exec.associate-5.sentence-1)

If other.*sndr*.has_value() is false,
no further effects;
otherwise,
calls *token*.try_associate() and,
if that returns true,
calls *sndr*.emplace(*other.*sndr*) and,
if that exits with an exception,
calls *token*.disassociate() before propagating the exception[.](#exec.associate-5.sentence-2)

[ð](#lib:execution::associate-data,constructor_)

`associate-data(associate-data&& other)
  noexcept(is_nothrow_move_constructible_v<wrap-sender>);
`

[6](#exec.associate-6)

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

*Effects*: Initializes *sndr* with std​::​move(other.*sndr*) and
initializes *token* with std​::​move(other.​*token*) and
then calls other.*sndr*.reset()[.](#exec.associate-6.sentence-1)

[ð](#lib:execution::associate-data,destructor)

`~associate-data();
`

[7](#exec.associate-7)

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

*Effects*: If *sndr*.has_value() returns false then no effect;
otherwise, invokes *sndr*.reset() before invoking *token*.disassociate()[.](#exec.associate-7.sentence-1)

[ð](#lib:release,execution::associate-data)

`optional<pair<Token, wrap-sender>>
  release() && noexcept(is_nothrow_move_constructible_v<wrap-sender>);
`

[8](#exec.associate-8)

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

*Effects*: If *sndr*.has_value() returns false then
returns an optional that does not contain a value;
otherwise returns an optional containing a value of type pair<Token, *wrap-sender*> as if by:return optional(pair(*token*, std::move(**sndr*)));

[9](#exec.associate-9)

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

*Postconditions*: *sndr* does not contain a value[.](#exec.associate-9.sentence-1)

[10](#exec.associate-10)

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

The name associate denotes a pipeable sender adaptor object[.](#exec.associate-10.sentence-1)

For subexpressions sndr and token:

- [(10.1)](#exec.associate-10.1)

If decltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"), orremove_cvref_t<decltype((token))> does not satisfy [scope_token](exec.scope.concepts#concept:scope_token "33.14.1 Execution scope concepts [exec.scope.concepts]"), thenassociate(sndr, token) is ill-formed.

- [(10.2)](#exec.associate-10.2)

Otherwise,
the expression associate(sndr, token) is expression-equivalent to:transform_sender(*get-domain-early*(sndr), *make-sender*(associate, *associate-data*(token, sndr))) except that sndr is evaluated only once.

[11](#exec.associate-11)

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

The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
is specialized for associate_t as follows:

[ð](#lib:execution::impls-for%3cassociate_t%3e)

namespace std::execution {template<>struct *impls-for*<associate_t> : *default-impls* {static constexpr auto *get-state* = *see below*; // *exposition only*static constexpr auto *start* = *see below*; // *exposition only*template<class Sndr, class... Env>static consteval void *check-types*() { // *exposition only*using associate_data_t = remove_cvref_t<*data-type*<Sndr>>; using child_type_t = typename associate_data_t::*wrap-sender*; (void)get_completion_signatures<child_type_t, *FWD-ENV-T*(Env)...>(); }};}

[12](#exec.associate-12)

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

The member *impls-for*<associate_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*) {auto [_, data] = std::forward<Sndr>(sndr); auto dataParts = std::move(data).release(); using scope_tkn = decltype(dataParts->first); using wrap_sender = decltype(dataParts->second); using op_t = connect_result_t<wrap_sender, Rcvr>; struct op_state {bool *associated* = false; // *exposition only*union { Rcvr* *rcvr*; // *exposition only*struct { scope_tkn *token*; // *exposition only* op_t *op*; // *exposition only*} *assoc*; // *exposition only*}; explicit op_state(Rcvr& r) noexcept: *rcvr*(addressof(r)) {}explicit op_state(scope_tkn tkn, wrap_sender&& sndr, Rcvr& r) try: *associated*(true), *assoc*(tkn, connect(std::move(sndr), std::move(r))) {}catch (...) { tkn.disassociate(); throw; } op_state(op_state&&) = delete; ~op_state() {if (*associated*) {*assoc*.*op*.~op_t(); *assoc*.*token*.disassociate(); *assoc*.*token*.~scope_tkn(); }}void *run*() noexcept { // *exposition only*if (*associated*) start(*assoc*.*op*); else set_stopped(std::move(**rcvr*)); }}; if (dataParts)return op_state{std::move(dataParts->first), std::move(dataParts->second), rcvr}; elsereturn op_state{rcvr};}

[13](#exec.associate-13)

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

The expression in the noexcept clause of*impls-for*<associate_t>​::​*get-state* isis_nothrow_constructible_v<remove_cvref_t<Sndr>, Sndr> && is_nothrow_move_constructible_v<*wrap-sender*> &&[*nothrow-callable*](functional.syn#concept:nothrow-callable "22.10.2 Header <functional> synopsis [functional.syn]")<connect_t, *wrap-sender*, Rcvr> where *wrap-sender* is the typeremove_cvref_t<*data-type*<Sndr>>​::​*wrap-sender*[.](#exec.associate-13.sentence-1)

[14](#exec.associate-14)

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

The member *impls-for*<associate_t>​::​*start* is initialized with a callable object equivalent to the following lambda:[](auto& state, auto&) noexcept -> void { state.*run*();}

[15](#exec.associate-15)

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

The evaluation of associate(sndr, token) may cause side effects observable
via token's associated async scope object[.](#exec.associate-15.sentence-1)

#### [33.9.12.17](#exec.stop.when) Exposition-only execution​::​*stop-when* [[exec.stop.when]](exec.stop.when)

[1](#exec.stop.when-1)

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

*stop-when* fuses an additional stop token t into a sender so that, upon connecting to a receiver r,
the resulting operation state receives stop requests from botht and the token returned from get_stop_token(get_env(r))[.](#exec.stop.when-1.sentence-1)

[2](#exec.stop.when-2)

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

The name *stop-when* denotes an exposition-only sender adaptor[.](#exec.stop.when-2.sentence-1)

For subexpressions sndr and token:

- [(2.1)](#exec.stop.when-2.1)

  If decltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"), orremove_cvref_t<decltype((token))> does not satisfy [stoppable_token](stoptoken.concepts#concept:stoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]"),
then *stop-when*(sndr, token) is ill-formed[.](#exec.stop.when-2.1.sentence-1)

- [(2.2)](#exec.stop.when-2.2)

  Otherwise,
if remove_cvref_t<decltype((token))> models[unstoppable_token](stoptoken.concepts#concept:unstoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]") then*stop-when*(​sndr, token) is expression-equivalent tosndr[.](#exec.stop.when-2.2.sentence-1)

- [(2.3)](#exec.stop.when-2.3)

  Otherwise,*stop-when*(sndr, token) returns a sender osndr[.](#exec.stop.when-2.3.sentence-1)
  If osndr is connected to a receiver r,
let rtoken be the result of get_stop_token(get_env(r))[.](#exec.stop.when-2.3.sentence-2)

  * [(2.3.1)](#exec.stop.when-2.3.1)

      If the type of rtoken models [unstoppable_token](stoptoken.concepts#concept:unstoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]") then
the effects of connecting osndr to r are equivalent toconnect(write_env(sndr, prop(get_stop_token, token)), r)[.](#exec.stop.when-2.3.1.sentence-1)

  * [(2.3.2)](#exec.stop.when-2.3.2)

      Otherwise,
the effects of connecting osndr to r are equivalent toconnect(write_env(sndr, prop(get_stop_token, stoken)), r) where stoken is an object of
an exposition-only type *stoken-t* such that:
    +
          [(2.3.2.1)](#exec.stop.when-2.3.2.1)
*stoken-t* models [stoppable_token](stoptoken.concepts#concept:stoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]");

    +
          [(2.3.2.2)](#exec.stop.when-2.3.2.2)
stoken.stop_requested() returns token.stop_requested() || rtoken.stop_reques-  
ted();

    +
          [(2.3.2.3)](#exec.stop.when-2.3.2.3)
stoken.stop_possible() returns token.stop_possible() || rtoken.stop_possible(); and

    +
          [(2.3.2.4)](#exec.stop.when-2.3.2.4)
for types Fn and Init such that both [invocable](concept.invocable#concept:invocable "18.7.2 Concept invocable [concept.invocable]")<Fn> and [constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept constructible_­from [concept.constructible]")<Fn, Init> are modeled, *stoken-t*​::​callback_type<Fn> models [*stoppable-callback-for*](stoptoken.concepts#concept:stoppable-callback-for "32.3.3 Stop token concepts [stoptoken.concepts]")<Fn, *stoken-t*, Init>[.](#exec.stop.when-2.3.2.sentence-1)
          [*Note [1](#exec.stop.when-note-1)*:
          For an object fn of type Fn constructed from a value, init, of type Init,
 registering fn using *stoken-t*​::​callback_type<Fn>(stoken, init) results in an invocation of fn when
 a callback registered with token or rtoken would be invoked[.](#exec.stop.when-2.3.2.4.sentence-2)
          fn is invoked at most once[.](#exec.stop.when-2.3.2.4.sentence-3)
 â *end note*]

#### [33.9.12.18](#exec.spawn.future) execution​::​spawn_future [[exec.spawn.future]](exec.spawn.future)

[1](#exec.spawn.future-1)

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

spawn_future attempts to associate the given input sender
with the given token's async scope and, on success,
eagerly starts the input sender;
the return value is a sender that, when connected and started,
completes with either
the result of the eagerly-started input sender or withset_stopped if the input sender was not started[.](#exec.spawn.future-1.sentence-1)

[2](#exec.spawn.future-2)

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

The name spawn_future denotes a customization point object[.](#exec.spawn.future-2.sentence-1)

For subexpressions sndr, token, and env,

- [(2.1)](#exec.spawn.future-2.1)

let Sndr be decltype((sndr)),

- [(2.2)](#exec.spawn.future-2.2)

let Token be remove_cvref_t<decltype((token))>, and

- [(2.3)](#exec.spawn.future-2.3)

let Env be remove_cvref_t<decltype((env))>[.](#exec.spawn.future-2.sentence-2)

If any of[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr>,[scope_token](exec.scope.concepts#concept:scope_token "33.14.1 Execution scope concepts [exec.scope.concepts]")<Token>, or[*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]")<Env> are not satisfied,
the expression spawn_future(sndr, token, env) is ill-formed[.](#exec.spawn.future-2.sentence-3)

[3](#exec.spawn.future-3)

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

Let *spawn-future-state-base* be the exposition-only class template:

[ð](#lib:execution::spawn-future-state-base)

namespace std::execution {template<class Completions>struct *spawn-future-state-base*; // *exposition only*template<class... Sigs>struct *spawn-future-state-base*<completion_signatures<Sigs...>> { // *exposition only*using *variant-t* = *see below*; // *exposition only**variant-t* *result*; // *exposition only*virtual void *complete*() noexcept = 0; // *exposition only*};}

[4](#exec.spawn.future-4)

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

Let Sigs be the pack of arguments to
the completion_signatures specialization provided as
a parameter to the *spawn-future-state-base* class template[.](#exec.spawn.future-4.sentence-1)

Let *as-tuple* be an alias template that
transforms a completion signature Tag(Args...) into the tuple specialization *decayed-tuple*<Tag, Args...>[.](#exec.spawn.future-4.sentence-2)

- [(4.1)](#exec.spawn.future-4.1)

  If is_nothrow_constructible_v<decay_t<Arg>, Arg> is true for every type Arg in every parameter pack Args in every completion signature Tag(Args...) in Sigs then*variant-t* denotes the typevariant<monostate, tuple<set_stopped_t>, *as-tuple*<Sigs>...>,
except with duplicate types removed[.](#exec.spawn.future-4.1.sentence-1)

- [(4.2)](#exec.spawn.future-4.2)

  Otherwise*variant-t* denotes the typevariant<monostate, tuple<set_stopped_t>, tuple<set_error_t, exception_ptr>, *as-tuple*<Sigs>...>,
except with duplicate types removed[.](#exec.spawn.future-4.2.sentence-1)

[5](#exec.spawn.future-5)

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

Let *spawn-future-receiver* be the exposition-only class template:

[ð](#lib:execution::spawn-future-receiver)

namespace std::execution {template<class Completions>struct *spawn-future-receiver* { // *exposition only*using receiver_concept = receiver_t; *spawn-future-state-base*<Completions>* *state*; // *exposition only*template<class... T>void set_value(T&&... t) && noexcept {*set-complete*<set_value_t>(std::forward<T>(t)...); }template<class E>void set_error(E&& e) && noexcept {*set-complete*<set_error_t>(std::forward<E>(e)); }void set_stopped() && noexcept {*set-complete*<set_stopped_t>(); }private:template<class CPO, class... T>void *set-complete*(T&&... t) noexcept { // *exposition only*constexpr bool nothrow = (is_nothrow_constructible_v<decay_t<T>, T> && ...); try {*state*->*result*.template emplace<*decayed-tuple*<CPO, T...>>(CPO{},
 std::forward<T>(t)...); }catch (...) {if constexpr (!nothrow) {using tuple_t = *decayed-tuple*<set_error_t, exception_ptr>; *state*->*result*.template emplace<tuple_t>(set_error_t{}, current_exception()); }}*state*->*complete*(); }};}

[6](#exec.spawn.future-6)

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

Let *ssource-t* be an unspecified type
that models [*stoppable-source*](stoptoken.concepts#concept:stoppable-source "32.3.3 Stop token concepts [stoptoken.concepts]") and
let ssource be an lvalue of type *ssource-t*[.](#exec.spawn.future-6.sentence-1)

Let *stoken-t* be decltype(ssource.get_token())[.](#exec.spawn.future-6.sentence-2)

Let *future-spawned-sender* be the alias template:

template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender, class Env>using *future-spawned-sender* = // *exposition only*decltype(write_env(*stop-when*(declval<Sender>(), declval<*stoken-t*>()), declval<Env>()));

[7](#exec.spawn.future-7)

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

Let *spawn-future-state* be the exposition-only class template:

[ð](#lib:execution::spawn-future-state)

namespace std::execution {template<class Alloc, [scope_token](exec.scope.concepts#concept:scope_token "33.14.1 Execution scope concepts [exec.scope.concepts]") Token, [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender, class Env>struct *spawn-future-state* // *exposition only*: *spawn-future-state-base*<completion_signatures_of_t<*future-spawned-sender*<Sender, Env>>> {using *sigs-t* = // *exposition only* completion_signatures_of_t<*future-spawned-sender*<Sender, Env>>; using *receiver-t* = // *exposition only**spawn-future-receiver*<*sigs-t*>; using *op-t* = // *exposition only* connect_result_t<*future-spawned-sender*<Sender, Env>, *receiver-t*>; *spawn-future-state*(Alloc alloc, Sender&& sndr, Token token, Env env) // *exposition only*: *alloc*(std::move(alloc)), *op*(connect( write_env(*stop-when*(std::forward<Sender>(sndr), *ssource*.get_token()), std::move(env)), *receiver-t*(this))), *token*(std::move(token)), *associated*(token.try_associate()) {if (associated) start(*op*); else set_stopped(*receiver-t*(this)); }void *complete*() noexcept override; // *exposition only*void *consume*([receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") auto& rcvr) noexcept; // *exposition only*void *abandon*() noexcept; // *exposition only*private:using *alloc-t* = // *exposition only*typename allocator_traits<Alloc>::template rebind_alloc<*spawn-future-state*>; *alloc-t* *alloc*; // *exposition only**ssource-t* *ssource*; // *exposition only**op-t* *op*; // *exposition only* Token *token*; // *exposition only*bool *associated*; // *exposition only*void *destroy*() noexcept; // *exposition only*};}

[8](#exec.spawn.future-8)

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

For purposes of determining the existence of a data race,*complete*, *consume*, and *abandon* behave as atomic operations ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"))[.](#exec.spawn.future-8.sentence-1)

These operations on a single object of a type
that is a specialization of *spawn-future-state* appear to occur in a single total order[.](#exec.spawn.future-8.sentence-2)

[ð](#lib:complete,execution::spawn-future-state)

`void complete() noexcept;
`

[9](#exec.spawn.future-9)

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

*Effects*: 

- [(9.1)](#exec.spawn.future-9.1)

No effects if this invocation of *complete* happens before
an invocation of *consume* or *abandon* on *this;

- [(9.2)](#exec.spawn.future-9.2)

otherwise,
if an invocation of *consume* on *this happens before
this invocation of *complete* then
there is a receiver, rcvr, registered and
that receiver is completed as if by *consume*(rcvr);

- [(9.3)](#exec.spawn.future-9.3)

otherwise,*destroy* is invoked[.](#exec.spawn.future-9.sentence-1)

[ð](#lib:consume,execution::spawn-future-state)

`void consume([receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") auto& rcvr) noexcept;
`

[10](#exec.spawn.future-10)

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

*Effects*: 

- [(10.1)](#exec.spawn.future-10.1)

If this invocation of *consume* happens before
an invocation of *complete* on *this thenrcvr is registered to be completed when*complete* is subsequently invoked on *this;

- [(10.2)](#exec.spawn.future-10.2)

otherwise,rcvr is completed as if by:std::move(this->*result*).visit([&rcvr](auto&& tuple) noexcept {if constexpr (![same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")<remove_reference_t<decltype(tuple)>, monostate>) { apply([&rcvr](auto cpo, auto&&... vals) { cpo(std::move(rcvr), std::move(vals)...); }, std::move(tuple)); }});

[ð](#lib:abandon,execution::spawn-future-state)

`void abandon() noexcept;
`

[11](#exec.spawn.future-11)

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

*Effects*: 

- [(11.1)](#exec.spawn.future-11.1)

If this invocation of *abandon* happens before
an invocation of *complete* on *this then
equivalent to:*ssource*.request_stop();

- [(11.2)](#exec.spawn.future-11.2)

otherwise,*destroy* is invoked[.](#exec.spawn.future-11.sentence-1)

[ð](#lib:destroy,execution::spawn-future-state)

`void destroy() noexcept;
`

[12](#exec.spawn.future-12)

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

*Effects*: Equivalent to:auto token = std::move(this->*token*);bool associated = this->*associated*;

{auto alloc = std::move(this->*alloc*);

 allocator_traits<*alloc-t*>::destroy(alloc, this);
 allocator_traits<*alloc-t*>::deallocate(alloc, this, 1);}if (associated) token.disassociate();

[13](#exec.spawn.future-13)

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

The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
is specialized for spawn_future_t as follows:

[ð](#lib:execution::impls-for%3cspawn_future_t%3e)

namespace std::execution {template<>struct *impls-for*<spawn_future_t> : *default-impls* {static constexpr auto *start* = *see below*; // *exposition only*};}

[14](#exec.spawn.future-14)

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

The member *impls-for*<spawn_future_t>​::​*start* is initialized with a callable object equivalent to the following lambda:[](auto& state, auto& rcvr) noexcept -> void { state->*consume*(rcvr);}

[15](#exec.spawn.future-15)

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

For the expression spawn_future(sndr, token, env) let new_sender be the expression token.wrap(sndr) and
let alloc and senv be defined as follows:

- [(15.1)](#exec.spawn.future-15.1)

if the expression get_allocator(env) is well-formed, thenalloc is the result of get_allocator(env) andsenv is the expression env;

- [(15.2)](#exec.spawn.future-15.2)

otherwise,
if the expression get_allocator(get_env(new_sender)) is well-formed, thenalloc is the result of get_allocator(get_env(new_sender)) andsenv is the expression*JOIN-ENV*(prop(get_allocator, alloc), env);

- [(15.3)](#exec.spawn.future-15.3)

otherwise,alloc is allocator<void>() andsenv is the expression env[.](#exec.spawn.future-15.sentence-1)

[16](#exec.spawn.future-16)

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

The expression spawn_future(sndr, token, env) has the following effects:

- [(16.1)](#exec.spawn.future-16.1)

  Uses alloc to allocate and construct an object s of
a type that is a specialization of *spawn-future-​state* from alloc, token.wrap(sndr), token, and senv[.](#exec.spawn.future-16.1.sentence-1)
  If an exception is thrown then
any constructed objects are destroyed and
any allocated memory is deallocated[.](#exec.spawn.future-16.1.sentence-2)

- [(16.2)](#exec.spawn.future-16.2)

  Constructs an object u of
a type that is a specialization of unique_ptr such that:
  * [(16.2.1)](#exec.spawn.future-16.2.1)

u.get() is equal to the address of s, and

  * [(16.2.2)](#exec.spawn.future-16.2.2)

u.get_deleter()(u.release()) is equivalent to u.release()->*abandon*()[.](#exec.spawn.future-16.2.sentence-1)

- [(16.3)](#exec.spawn.future-16.3)

  Returns *make-sender*(spawn_future, std​::​move(u))[.](#exec.spawn.future-16.3.sentence-1)

[17](#exec.spawn.future-17)

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

The expression spawn_future(sndr, token) is expression-equivalent tospawn_future(sndr, token, execution​::​env<>())[.](#exec.spawn.future-17.sentence-1)
