[exec.schedule.from] # 33 Execution control library [[exec]](./#exec) ## 33.9 Senders [[exec.snd]](exec.snd#exec.schedule.from) ### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#exec.schedule.from) #### 33.9.12.7 execution​::​schedule_from [exec.schedule.from] [1](#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[.](#1.sentence-1) [*Note [1](#note-1)*: schedule_from is not meant to be used in user code; it is used in the implementation of continues_on[.](#1.sentence-2) — *end note*] [2](#2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3367) The name schedule_from denotes a customization point object[.](#2.sentence-1) For some subexpressions sch and sndr, let Sch be decltype((sch)) andSndr be decltype((sndr))[.](#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[.](#2.sentence-3) [3](#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[.](#3.sentence-1) [4](#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* : *default-impls* {static constexpr auto *get-attrs* = *see below*; static constexpr auto *get-state* = *see below*; static constexpr auto *complete* = *see below*; templatestatic consteval void *check-types*(); };} [5](#5) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3404) The member *impls-for*​::​*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](#6) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3413) The member *impls-for*​::​*get-state* is initialized with a callable object equivalent to the following lambda:[](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*, *FWD-ENV-T*(env_of_t)> {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, 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 static consteval void check-types(); ` [7](#7) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3448) *Effects*: Equivalent to:get_completion_signatures>, *FWD-ENV-T*(Env)...>();auto cs = get_completion_signatures<*child-type*, *FWD-ENV-T*(Env)...>();*decay-copyable-result-datums*(cs); // see [[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities") [8](#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[.](#8.sentence-1) [9](#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*, *FWD-ENV-T*(env_of_t)>[.](#9.sentence-1) Let *as-tuple* be an alias template such that*as-tuple* denotes the type *decayed-tuple*, and let *is-nothrow-decay-copy-sig* be a variable template such thatauto(*is-nothrow-decay-copy-sig*) is a constant expression of type bool and equal to (is_nothrow_constructible_v, Args> && ...)[.](#9.sentence-2) Let *error-completion* be a pack consisting of the type set_error_t(exception_ptr) if (*is-nothrow-decay-copy-sig* &&...) is false, and an empty pack otherwise[.](#9.sentence-3) Then variant_t denotes the type variant..., *error-completion*...>, except with duplicate types removed[.](#9.sentence-4) [10](#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](Tuple& result) noexcept -> void {if constexpr (![same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")) {auto& [tag, ...args] = result; tag(std::move(*state*->*rcvr*), std::move(args)...); }}, *state*->*async-result*); }templatevoid set_error(Error&& err) && noexcept { execution::set_error(std::move(*state*->*rcvr*), std::forward(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](#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[.](#11.sentence-1) [12](#12) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3522) The member *impls-for*​::​*complete* is initialized with a callable object equivalent to the following lambda:[](auto, auto& state, auto& rcvr, Tag, Args&&... args) noexcept-> void {using result_t = *decayed-tuple*; constexpr bool nothrow = (is_nothrow_constructible_v, Args> && ...); try { state.*async-result*.template emplace(Tag(), std::forward(args)...); } catch (...) {if constexpr (!nothrow) state.*async-result*.template emplace>(set_error, current_exception()); } start(state.*op-state*);}; [13](#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))[.](#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]") is true[.](#13.sentence-2) Let op be an lvalue referring to the operation state that results from connecting out_sndr with out_rcvr[.](#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[.](#13.sentence-4) If scheduling onto sch fails, an error completion on out_rcvr shall be executed on an unspecified execution agent[.](#13.sentence-5)