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