This commit is contained in:
2025-10-25 03:02:53 +03:00
commit 043225d523
3416 changed files with 681196 additions and 0 deletions

948
cppdraft/exec/coro/util.md Normal file
View File

@@ -0,0 +1,948 @@
[exec.coro.util]
# 33 Execution control library [[exec]](./#exec)
## 33.13 Coroutine utilities [exec.coro.util]
### [33.13.1](#exec.as.awaitable) execution::as_awaitable [[exec.as.awaitable]](exec.as.awaitable)
[1](#exec.as.awaitable-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6609)
as_awaitable transforms an object into one
that is awaitable within a particular coroutine[.](#exec.as.awaitable-1.sentence-1)
Subclause [exec.coro.util] makes use of
the following exposition-only entities:namespace std::execution {template<class Sndr, class Promise>concept [*awaitable-sender*](#concept:awaitable-sender "33.13.1execution::as_­awaitable[exec.as.awaitable]") =[*single-sender*](execution.syn#concept:single-sender "33.4Header <execution> synopsis[execution.syn]")<Sndr, env_of_t<Promise>> &&[sender_to](exec.snd.concepts#concept:sender_to "33.9.3Sender concepts[exec.snd.concepts]")<Sndr, *awaitable-receiver*> && // *see below*requires (Promise& p) {{ p.unhandled_stopped() } -> [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<coroutine_handle<>>; }; template<class Sndr>concept [*has-queryable-await-completion-adaptor*](#concept:has-queryable-await-completion-adaptor "33.13.1execution::as_­awaitable[exec.as.awaitable]") = // *exposition only*[sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]")<Sndr> &&requires(Sndr&& sender) { get_await_completion_adaptor(get_env(sender)); }; template<class Sndr, class Promise>class *sender-awaitable*; // *exposition only*}
[2](#exec.as.awaitable-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6636)
The type *sender-awaitable*<Sndr, Promise> is equivalent to:
namespace std::execution {template<class Sndr, class Promise>class *sender-awaitable* {struct *unit* {}; // *exposition only*using *value-type* = // *exposition only**single-sender-value-type*<Sndr, env_of_t<Promise>>; using *result-type* = // *exposition only* conditional_t<is_void_v<*value-type*>, unit, *value-type*>; struct *awaitable-receiver*; // *exposition only* variant<monostate, *result-type*, exception_ptr> *result*{}; // *exposition only* connect_result_t<Sndr, *awaitable-receiver*> *state*; // *exposition only*public:*sender-awaitable*(Sndr&& sndr, Promise& p); static constexpr bool await_ready() noexcept { return false; }void await_suspend(coroutine_handle<Promise>) noexcept { start(*state*); }*value-type* await_resume(); };}
[3](#exec.as.awaitable-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6662)
*awaitable-receiver* is equivalent to:struct *awaitable-receiver* {using receiver_concept = receiver_t;
variant<monostate, *result-type*, exception_ptr>* *result-ptr*; // *exposition only* coroutine_handle<Promise> *continuation*; // *exposition only*// *see below*};
[4](#exec.as.awaitable-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6673)
Let rcvr be an rvalue expression of type *awaitable-receiver*,
let crcvr be a const lvalue that refers to rcvr,
let vs be a pack of subexpressions, and
let err be an expression of type Err[.](#exec.as.awaitable-4.sentence-1)
Then:
- [(4.1)](#exec.as.awaitable-4.1)
If [constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<*result-type*, decltype((vs))...> is satisfied,
the expression set_value(
rcvr, vs...) is equivalent to:try { rcvr.*result-ptr*->template emplace<1>(vs...);} catch(...) { rcvr.*result-ptr*->template emplace<2>(current_exception());} rcvr.*continuation*.resume();
Otherwise, set_value(rcvr, vs...) is ill-formed[.](#exec.as.awaitable-4.1.sentence-2)
- [(4.2)](#exec.as.awaitable-4.2)
The expression set_error(rcvr, err) is equivalent to:rcvr.*result-ptr*->template emplace<2>(*AS-EXCEPT-PTR*(err)); // see [[exec.general]](exec.general "33.1General") rcvr.*continuation*.resume();
- [(4.3)](#exec.as.awaitable-4.3)
The expression set_stopped(rcvr) is equivalent to:static_cast<coroutine_handle<>>(rcvr.*continuation*.promise().unhandled_stopped()).resume();
- [(4.4)](#exec.as.awaitable-4.4)
For any expression tag whose type satisfies [*forwarding-query*](execution.syn#concept:forwarding-query "33.4Header <execution> synopsis[execution.syn]") and
for any pack of subexpressions as,get_env(crcvr).query(tag, as...) is expression-equivalent to:tag(get_env(as_const(crcvr.*continuation*.promise())), as...)
[🔗](#exec.as.awaitable-itemdecl:1)
`sender-awaitable(Sndr&& sndr, Promise& p);
`
[5](#exec.as.awaitable-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6718)
*Effects*: Initializes *state* withconnect(std::forward<Sndr>(sndr), *awaitable-receiver*{addressof(result), coroutine_handle<Promise>::from_promise(p)})
[🔗](#exec.as.awaitable-itemdecl:2)
`value-type await_resume();
`
[6](#exec.as.awaitable-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6732)
*Effects*: Equivalent to:if (*result*.index() == 2) rethrow_exception(get<2>(*result*));if constexpr (!is_void_v<*value-type*>)return std::forward<*value-type*>(get<1>(*result*));
[7](#exec.as.awaitable-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6743)
as_awaitable is a customization point object[.](#exec.as.awaitable-7.sentence-1)
For subexpressions expr and p where p is an lvalue,Expr names the type decltype((expr)) andPromise names the type decay_t<decltype((p))>,as_awaitable(expr, p) is expression-equivalent to,
except that the evaluations of expr and p are indeterminately sequenced:
- [(7.1)](#exec.as.awaitable-7.1)
expr.as_awaitable(p) if that expression is well-formed[.](#exec.as.awaitable-7.1.sentence-1)
*Mandates*: [*is-awaitable*](exec.awaitable#concept:is-awaitable "33.9.4Awaitable helpers[exec.awaitable]")<A, Promise> is true,
where A is the type of the expression above[.](#exec.as.awaitable-7.1.sentence-2)
- [(7.2)](#exec.as.awaitable-7.2)
Otherwise, (void(p), expr) if [*is-awaitable*](exec.awaitable#concept:is-awaitable "33.9.4Awaitable helpers[exec.awaitable]")<Expr, U> is true,
where U is an unspecified class type
that is not Promise and
that lacks a member named await_transform[.](#exec.as.awaitable-7.2.sentence-1)
*Preconditions*: [*is-awaitable*](exec.awaitable#concept:is-awaitable "33.9.4Awaitable helpers[exec.awaitable]")<Expr, Promise> is true and
the expression co_await expr in a coroutine with promise type U is expression-equivalent to
the same expression in a coroutine with promise type Promise[.](#exec.as.awaitable-7.2.sentence-2)
- [(7.3)](#exec.as.awaitable-7.3)
Otherwise, *sender-awaitable*{*adapted-expr*, p} if*has-queryable-await-completion-adaptor*<Expr> and*awaitable-sender*<decltype((*adapted-expr*)), Promise> are both satisfied, where *adapted-expr* isget_await_completion_adaptor(get_env(expr))(expr),
except that expr is evaluated only once[.](#exec.as.awaitable-7.3.sentence-1)
- [(7.4)](#exec.as.awaitable-7.4)
Otherwise, *sender-awaitable*{expr, p} if [*awaitable-sender*](#concept:awaitable-sender "33.13.1execution::as_­awaitable[exec.as.awaitable]")<Expr, Promise> is true[.](#exec.as.awaitable-7.4.sentence-1)
- [(7.5)](#exec.as.awaitable-7.5)
Otherwise, (void(p), expr)[.](#exec.as.awaitable-7.5.sentence-1)
### [33.13.2](#exec.with.awaitable.senders) execution::with_awaitable_senders [[exec.with.awaitable.senders]](exec.with.awaitable.senders)
[1](#exec.with.awaitable.senders-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6793)
with_awaitable_senders,
when used as the base class of a coroutine promise type,
makes senders awaitable in that coroutine type[.](#exec.with.awaitable.senders-1.sentence-1)
In addition, it provides a default implementation of unhandled_stopped such that if a sender completes by calling set_stopped,
it is treated as if an uncatchable "stopped" exception were thrown
from the [*await-expression*](expr.await#nt:await-expression "7.6.2.4Await[expr.await]")[.](#exec.with.awaitable.senders-1.sentence-2)
[*Note [1](#exec.with.awaitable.senders-note-1)*:
The coroutine is never resumed, and
the unhandled_stopped of the coroutine caller's promise type is called[.](#exec.with.awaitable.senders-1.sentence-3)
— *end note*]
namespace std::execution {template<[*class-type*](execution.syn#concept:class-type "33.4Header <execution> synopsis[execution.syn]") Promise>struct [with_awaitable_senders](#lib:with_awaitable_senders "33.13.2execution::with_­awaitable_­senders[exec.with.awaitable.senders]") {template<class OtherPromise>requires (![same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<OtherPromise, void>)void set_continuation(coroutine_handle<OtherPromise> h) noexcept;
coroutine_handle<> [continuation](#lib:with_awaitable_senders,continuation "33.13.2execution::with_­awaitable_­senders[exec.with.awaitable.senders]")() const noexcept { return *continuation*; } coroutine_handle<> [unhandled_stopped](#lib:with_awaitable_senders,unhandled_stopped "33.13.2execution::with_­awaitable_­senders[exec.with.awaitable.senders]")() noexcept {return *stopped-handler*(*continuation*.address()); }template<class Value>*see below* await_transform(Value&& value); private:[[noreturn]] static coroutine_handle<>*default-unhandled-stopped*(void*) noexcept { // *exposition only* terminate(); } coroutine_handle<> *continuation*{}; // *exposition only* coroutine_handle<> (**stopped-handler*)(void*) noexcept = // *exposition only*&*default-unhandled-stopped*; };}
[🔗](#lib:set_continuation,with_awaitable_senders)
`template<class OtherPromise>
requires (![same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<OtherPromise, void>)
void set_continuation(coroutine_handle<OtherPromise> h) noexcept;
`
[2](#exec.with.awaitable.senders-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6844)
*Effects*: Equivalent to:*continuation* = h;if constexpr ( requires(OtherPromise& other) { other.unhandled_stopped(); } ) {*stopped-handler* = [](void* p) noexcept -> coroutine_handle<> {return coroutine_handle<OtherPromise>::from_address(p).promise().unhandled_stopped(); };} else {*stopped-handler* = &*default-unhandled-stopped*;}
[🔗](#lib:await_transform,with_awaitable_senders)
`template<class Value>
call-result-t<as_awaitable_t, Value, Promise&> await_transform(Value&& value);
`
[3](#exec.with.awaitable.senders-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6867)
*Effects*: Equivalent to:return as_awaitable(std::forward<Value>(value), static_cast<Promise&>(*this));
### [33.13.3](#exec.affine.on) execution::affine_on [[exec.affine.on]](exec.affine.on)
[1](#exec.affine.on-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6877)
affine_on adapts a sender into one that completes on
the specified scheduler[.](#exec.affine.on-1.sentence-1)
If the algorithm determines that the adapted sender already completes
on the correct scheduler it can avoid any scheduling operation[.](#exec.affine.on-1.sentence-2)
[2](#exec.affine.on-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6883)
The name affine_on denotes a pipeable sender adaptor
object[.](#exec.affine.on-2.sentence-1)
For subexpressions sch and sndr, if decltype((sch)) does not satisfy [scheduler](exec.sched#concept:scheduler "33.6Schedulers[exec.sched]"), or decltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]"), affine_on(sndr, sch) is ill-formed[.](#exec.affine.on-2.sentence-2)
[3](#exec.affine.on-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6891)
Otherwise, the expression affine_on(sndr, sch) is
expression-equivalent to:transform_sender(*get-domain-early*(sndr), *make-sender*(affine_on, sch, sndr)) except that sndr is evaluated only once[.](#exec.affine.on-3.sentence-1)
[4](#exec.affine.on-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6899)
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2Exposition-only entities"))
is specialized for affine_on_t as follows:
namespace std::execution {template<>struct *impls-for*<affine_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.affine.on-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6915)
Let *out_sndr* be a subexpression denoting a sender
returned from affine_on(sndr, sch) or one equal to such,
and let *OutSndr* be the type decltype((*out_sndr*))[.](#exec.affine.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.3Sender concepts[exec.snd.concepts]")<*OutSndr*, Env> is true[.](#exec.affine.on-5.sentence-2)
Let *op* be an lvalue referring to the operation state that
results from connecting *out_sndr* to *out_rcvr*[.](#exec.affine.on-5.sentence-3)
Calling start(*op*) will start sndr on the current
execution agent and execute completion operations on *out_rcvr* on an execution agent of the execution resource associated withsch[.](#exec.affine.on-5.sentence-4)
If the current execution resource is the same as the execution
resource associated with sch, the completion operation on*out_rcvr* may be called before start(*op*) completes[.](#exec.affine.on-5.sentence-5)
If scheduling onto sch fails, an error completion on*out_rcvr* shall be executed on an unspecified execution
agent[.](#exec.affine.on-5.sentence-6)
### [33.13.4](#exec.inline.scheduler) execution::inline_scheduler [[exec.inline.scheduler]](exec.inline.scheduler)
namespace std::execution {class [inline_scheduler](#lib:inline_scheduler "33.13.4execution::inline_­scheduler[exec.inline.scheduler]") {class *inline-sender*; // *exposition only*template<[receiver](exec.recv.concepts#concept:receiver "33.7.1Receiver concepts[exec.recv.concepts]") R>class *inline-state*; // *exposition only*public:using scheduler_concept = scheduler_t; constexpr *inline-sender* schedule() noexcept { return {}; }constexpr bool operator==(const inline_scheduler&) const noexcept = default; };}
[1](#exec.inline.scheduler-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6954)
inline_scheduler is a class that models[scheduler](exec.sched#concept:scheduler "33.6Schedulers[exec.sched]") ([[exec.sched]](exec.sched "33.6Schedulers"))[.](#exec.inline.scheduler-1.sentence-1)
All objects of type inline_scheduler are equal[.](#exec.inline.scheduler-1.sentence-2)
[2](#exec.inline.scheduler-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6959)
*inline-sender* is an exposition-only type that satisfies[sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]")[.](#exec.inline.scheduler-2.sentence-1)
The type completion_signatures_of_t<*inline-sender*> is completion_signatures<set_value_t()>[.](#exec.inline.scheduler-2.sentence-2)
[3](#exec.inline.scheduler-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6965)
Let sndr be an expression of type *inline-sender*,
let rcvr be an expression such that[receiver_of](exec.recv.concepts#concept:receiver_of "33.7.1Receiver concepts[exec.recv.concepts]")<decltype((rcvr)), CS> is true where CS is completion_signatures<set_value_t()>,
then:
- [(3.1)](#exec.inline.scheduler-3.1)
the expression connect(sndr, rcvr) has
type *inline-state*<remove_cvref_t<decltype((rcvr))>> and is potentially-throwing if and only if((void)sndr, auto(rcvr)) is potentially-throwing, and
- [(3.2)](#exec.inline.scheduler-3.2)
the expressionget_completion_scheduler<set_value_t>(get_env(sndr)) has
type inline_scheduler and is potentially-throwing
if and only if get_env(sndr) is potentially-throwing[.](#exec.inline.scheduler-3.sentence-1)
[4](#exec.inline.scheduler-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6982)
Let *o* be a non-const lvalue of type*inline-state*<Rcvr>, and let REC(*o*) be
a non-const lvalue reference to an object of type Rcvr that
was initialized with the expression rcvr passed to an
invocation of connect that returned *o*, then:
- [(4.1)](#exec.inline.scheduler-4.1)
the object to which REC(*o*) refers remains valid for
the lifetime of the object to which *o* refers, and
- [(4.2)](#exec.inline.scheduler-4.2)
the expression start(*o*) is equivalent toset_value(std::move(REC(*o*)))[.](#exec.inline.scheduler-4.sentence-1)
### [33.13.5](#exec.task.scheduler) execution::task_scheduler [[exec.task.scheduler]](exec.task.scheduler)
namespace std::execution {class [task_scheduler](#lib:task_scheduler "33.13.5execution::task_­scheduler[exec.task.scheduler]") {class *ts-sender*; // *exposition only*template<[receiver](exec.recv.concepts#concept:receiver "33.7.1Receiver concepts[exec.recv.concepts]") R>class *state*; // *exposition only*public:using scheduler_concept = scheduler_t; template<class Sch, class Allocator = allocator<void>>requires (![same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<task_scheduler, remove_cvref_t<Sch>>)&& [scheduler](exec.sched#concept:scheduler "33.6Schedulers[exec.sched]")<Sch>explicit task_scheduler(Sch&& sch, Allocator alloc = {}); *ts-sender* schedule(); friend bool operator==(const task_scheduler& lhs, const task_scheduler& rhs)noexcept; template<class Sch>requires (![same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<task_scheduler, Sch>)&& [scheduler](exec.sched#concept:scheduler "33.6Schedulers[exec.sched]")<Sch>friend bool operator==(const task_scheduler& lhs, const Sch& rhs) noexcept; private: shared_ptr<void> *sch_*; // *exposition only*};}
[1](#exec.task.scheduler-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7028)
task_scheduler is a class that models[scheduler](exec.sched#concept:scheduler "33.6Schedulers[exec.sched]") ([[exec.sched]](exec.sched "33.6Schedulers"))[.](#exec.task.scheduler-1.sentence-1)
Given an object s of type task_scheduler, let*SCHED*(s) be the object owned by s.*sch_*[.](#exec.task.scheduler-1.sentence-2)
[🔗](#lib:task_scheduler,constructor)
`template<class Sch, class Allocator = allocator<void>>
requires(![same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<task_scheduler, remove_cvref_t<Sch>>) && [scheduler](exec.sched#concept:scheduler "33.6Schedulers[exec.sched]")<Sch>
explicit task_scheduler(Sch&& sch, Allocator alloc = {});
`
[2](#exec.task.scheduler-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7041)
*Effects*: Initialize *sch_* withallocate_shared<remove_cvref_t<Sch>>(alloc, std::forward<Sch>(sch))[.](#exec.task.scheduler-2.sentence-1)
[3](#exec.task.scheduler-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7046)
*Recommended practice*: Implementations should avoid the use of dynamically
allocated memory for small scheduler objects[.](#exec.task.scheduler-3.sentence-1)
[4](#exec.task.scheduler-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7051)
*Remarks*: Any allocations performed by construction of *ts-sender* or*state* objects resulting from calls on *this are
performed using a copy of alloc[.](#exec.task.scheduler-4.sentence-1)
[🔗](#lib:scheduler,task_scheduler)
`ts-sender schedule();
`
[5](#exec.task.scheduler-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7063)
*Effects*: Returns an object of type *ts-sender* containing a sender
initialized with schedule(*SCHED*(*this))[.](#exec.task.scheduler-5.sentence-1)
[🔗](#lib:operator==,task_scheduler)
`bool operator==(const task_scheduler& lhs, const task_scheduler& rhs) noexcept;
`
[6](#exec.task.scheduler-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7074)
*Effects*: Equivalent to: return lhs == *SCHED*(rhs);
[🔗](#lib:operator==,task_scheduler_)
`template<class Sch>
requires (![same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<task_scheduler, Sch>)
&& [scheduler](exec.sched#concept:scheduler "33.6Schedulers[exec.sched]")<Sch>
bool operator==(const task_scheduler& lhs, const Sch& rhs) noexcept;
`
[7](#exec.task.scheduler-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7087)
*Returns*: false if the type of *SCHED*(lhs) is not Sch,
otherwise *SCHED*(lhs) == rhs[.](#exec.task.scheduler-7.sentence-1)
[8](#exec.task.scheduler-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7093)
namespace std::execution {class task_scheduler::*ts-sender* { // *exposition only*public:using sender_concept = sender_t; template<[receiver](exec.recv.concepts#concept:receiver "33.7.1Receiver concepts[exec.recv.concepts]") Rcvr>*state*<Rcvr> connect(Rcvr&& rcvr); };}*ts-sender* is an exposition-only class that models[sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]") ([[exec.snd]](exec.snd "33.9Senders")) and for whichcompletion_signatures_of_t<*ts-sender*> denotes:completion_signatures< set_value_t(),
set_error_t(error_code),
set_error_t(exception_ptr),
set_stopped_t()>
[9](#exec.task.scheduler-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7116)
Let *sch* be an object of type task_scheduler and let sndr be an object of type *ts-sender* obtained
from schedule(*sch*)[.](#exec.task.scheduler-9.sentence-1)
Then get_completion_scheduler<set_value_t>(get_env(sndr)) == *sch* is true[.](#exec.task.scheduler-9.sentence-2)
The object *SENDER*(sndr) is the sender object contained bysndr or an object move constructed from it[.](#exec.task.scheduler-9.sentence-3)
[🔗](#lib:connect,task_scheduler::ts-sender)
`template<[receiver](exec.recv.concepts#concept:receiver "33.7.1Receiver concepts[exec.recv.concepts]") Rcvr>
state<Rcvr> connect(Rcvr&& rcvr);
`
[10](#exec.task.scheduler-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7131)
*Effects*: Let *r* be an object of a type that models [receiver](exec.recv.concepts#concept:receiver "33.7.1Receiver concepts[exec.recv.concepts]") and whose completion handlers result in invoking the corresponding
completion handlers of rcvr or copy thereof[.](#exec.task.scheduler-10.sentence-1)
Returns an object of type *state*<Rcvr> containing
an operation state object initialized with connect(*SENDER*(*this),
std::move(*r*))[.](#exec.task.scheduler-10.sentence-2)
[11](#exec.task.scheduler-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7141)
namespace std::execution {template<[receiver](exec.recv.concepts#concept:receiver "33.7.1Receiver concepts[exec.recv.concepts]") R>class task_scheduler::*state* { // *exposition only*public:using operation_state_concept = operation_state_t; void start() & noexcept; };}*state* is an exposition-only class template whose
specializations model [operation_state](exec.opstate.general#concept:operation_state "33.8.1General[exec.opstate.general]") ([[exec.opstate]](exec.opstate "33.8Operation states"))[.](#exec.task.scheduler-11.sentence-1)
[🔗](#lib:start,task_scheduler::state)
`void start() & noexcept;
`
[12](#exec.task.scheduler-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7161)
*Effects*: Equivalent to start(st) where st is the operation
state object contained by *this[.](#exec.task.scheduler-12.sentence-1)
### [33.13.6](#exec.task) execution::task [[exec.task]](exec.task)
#### [33.13.6.1](#task.overview) task overview [[task.overview]](task.overview)
[1](#task.overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7171)
The task class template represents a sender that can
be used as the return type of coroutines[.](#task.overview-1.sentence-1)
The first template parameter T defines the type of the value
completion datum ([[exec.async.ops]](exec.async.ops "33.3Asynchronous operations")) if T is not void[.](#task.overview-1.sentence-2)
Otherwise, there are no value completion datums[.](#task.overview-1.sentence-3)
Inside coroutines returning task<T, E> the operand ofco_return (if any) becomes the argument of set_value[.](#task.overview-1.sentence-4)
The second template parameter Environment is used to customize
the behavior of task[.](#task.overview-1.sentence-5)
#### [33.13.6.2](#task.class) Class template task [[task.class]](task.class)
namespace std::execution {template<class T, class Environment>class [task](#lib:task "33.13.6.2Class template task[task.class]") {// [[task.state]](#task.state "33.13.6.4Class template task::state")template<[receiver](exec.recv.concepts#concept:receiver "33.7.1Receiver concepts[exec.recv.concepts]") Rcvr>class *state*; // *exposition only*public:using sender_concept = sender_t; using completion_signatures = *see below*; using allocator_type = *see below*; using scheduler_type = *see below*; using stop_source_type = *see below*; using stop_token_type = decltype(declval<stop_source_type>().get_token()); using error_types = *see below*; // [[task.promise]](#task.promise "33.13.6.5Class task::promise_­type")class promise_type;
task(task&&) noexcept; ~task(); template<[receiver](exec.recv.concepts#concept:receiver "33.7.1Receiver concepts[exec.recv.concepts]") Rcvr>*state*<Rcvr> connect(Rcvr&& rcvr); private: coroutine_handle<promise_type> *handle*; // *exposition only*};}
[1](#task.class-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7216)
task<T, E> models [sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]") ([[exec.snd]](exec.snd "33.9Senders"))
if T is void, a reference type, or a cv-unqualified
non-array object type and E is a class type[.](#task.class-1.sentence-1)
Otherwise a program that instantiates the definition of task<T, E> is ill-formed[.](#task.class-1.sentence-2)
[2](#task.class-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7223)
The nested types of task template specializations
are determined based on the Environment parameter:
- [(2.1)](#task.class-2.1)
allocator_type is Environment::allocator_type if that [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3Qualified names[expr.prim.id.qual]") is valid and denotes a type,allocator<byte> otherwise[.](#task.class-2.1.sentence-1)
- [(2.2)](#task.class-2.2)
scheduler_type is Environment::scheduler_type if that [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3Qualified names[expr.prim.id.qual]") is valid and denotes a type,task_scheduler otherwise[.](#task.class-2.2.sentence-1)
- [(2.3)](#task.class-2.3)
stop_source_type is Environment::stop_source_type if that [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3Qualified names[expr.prim.id.qual]") is valid and denotes a type,inplace_stop_source otherwise[.](#task.class-2.3.sentence-1)
- [(2.4)](#task.class-2.4)
error_types is Environment::error_types if
that [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3Qualified names[expr.prim.id.qual]") is valid and denotes a type,completion_signatures<set_error_t(exception_ptr)> otherwise[.](#task.class-2.4.sentence-1)
[3](#task.class-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7241)
A program is ill-formed if error_types is not a
specialization of completion_signatures<ErrorSigs...> orErrorSigs contains an element which is not of the formset_error_t(E) for some type E[.](#task.class-3.sentence-1)
[4](#task.class-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7247)
The type alias completion_signatures is a specialization
of execution::completion_signatures with the template
arguments (in unspecified order):
- [(4.1)](#task.class-4.1)
set_value_t() if T is void,
and set_value_t(T) otherwise;
- [(4.2)](#task.class-4.2)
template arguments of the specialization ofexecution::completion_signatures denoted by error_types;
and
- [(4.3)](#task.class-4.3)
set_stopped_t()[.](#task.class-4.sentence-1)
[5](#task.class-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7260)
allocator_type shall meet the *Cpp17Allocator* requirements[.](#task.class-5.sentence-1)
#### [33.13.6.3](#task.members) task members [[task.members]](task.members)
[🔗](#lib:task,constructor)
`task(task&& other) noexcept;
`
[1](#task.members-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7271)
*Effects*: Initializes *handle* with exchange(other.*handle*,{})[.](#task.members-1.sentence-1)
[🔗](#lib:task,destructor)
`~task();
`
[2](#task.members-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7282)
*Effects*: Equivalent to:if (*handle*)*handle*.destroy();
[🔗](#lib:connect,task)
`template<[receiver](exec.recv.concepts#concept:receiver "33.7.1Receiver concepts[exec.recv.concepts]") Rcvr>
state<Rcvr> connect(Rcvr&& recv);
`
[3](#task.members-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7297)
*Preconditions*: bool(*handle*) is true[.](#task.members-3.sentence-1)
[4](#task.members-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7301)
*Effects*: Equivalent to:return *state*<Rcvr>(exchange(*handle*, {}), std::forward<Rcvr>(recv));
#### [33.13.6.4](#task.state) Class template task::*state* [[task.state]](task.state)
namespace std::execution {template<class T, class Environment>template<[receiver](exec.recv.concepts#concept:receiver "33.7.1Receiver concepts[exec.recv.concepts]") Rcvr>class task<T, Environment>::*state* { // *exposition only*public:using operation_state_concept = operation_state_t; template<class R>*state*(coroutine_handle<promise_type> h, R&& rr); ~*state*(); void start() & noexcept; private:using *own-env-t* = *see below*; // *exposition only* coroutine_handle<promise_type> *handle*; // *exposition only* remove_cvref_t<Rcvr> *rcvr*; // *exposition only**own-env-t* *own-env*; // *exposition only* Environment *environment*; // *exposition only*};}
[1](#task.state-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7336)
The type *own-env-t* is Environment::template env_type<decltype(get_env(declval<Rcvr>()))> if that[*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3Qualified names[expr.prim.id.qual]") is valid and denotes a type, env<> otherwise[.](#task.state-1.sentence-1)
[🔗](#lib:task::state,constructor)
`template<class R>
state(coroutine_handle<promise_type> h, R&& rr);
`
[2](#task.state-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7347)
*Effects*: Initializes
- [(2.1)](#task.state-2.1)
*handle* with std::move(h);
- [(2.2)](#task.state-2.2)
*rcvr* with std::forward<R>(rr);
- [(2.3)](#task.state-2.3)
*own-env* with *own-env-t*(get_env(*rcvr*)) if that expression
is valid and *own-env-t*() otherwise[.](#task.state-2.3.sentence-1)
If neither of these expressions is valid, the program is ill-formed[.](#task.state-2.3.sentence-2)
- [(2.4)](#task.state-2.4)
*environment* withEnvironment(*own-env*) if that expression is
valid, otherwise Environment(get_env(*rcvr*)) if this expression is valid, otherwise Environment()[.](#task.state-2.4.sentence-1)
If neither of these expressions is valid, the program is ill-formed[.](#task.state-2.4.sentence-2)
[🔗](#lib:task::state,destructor)
`~state();
`
[3](#task.state-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7370)
*Effects*: Equivalent to:if (*handle*)*handle*.destroy();
[🔗](#lib:start,task::state)
`void start() & noexcept;
`
[4](#task.state-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7384)
*Effects*: Let *prom* be the object *handle*.promise()[.](#task.state-4.sentence-1)
Associates *STATE*(*prom*), *RCVR*(*prom*), and *SCHED*(*prom*) with *this as follows:
- [(4.1)](#task.state-4.1)
*STATE*(*prom*) is *this[.](#task.state-4.1.sentence-1)
- [(4.2)](#task.state-4.2)
*RCVR*(*prom*) is *rcvr*[.](#task.state-4.2.sentence-1)
- [(4.3)](#task.state-4.3)
*SCHED*(*prom*) is the object initialized
with scheduler_type(get_scheduler(get_env(*rcvr*))) if that expression is valid and scheduler_type() otherwise[.](#task.state-4.3.sentence-1)
If neither of these expressions is valid, the program is ill-formed[.](#task.state-4.3.sentence-2)
Let *st* be get_stop_token(get_env(*rcvr*))[.](#task.state-4.sentence-3)
Initializes *prom*.*token* and*prom*.*source* such that
- [(4.4)](#task.state-4.4)
*prom*.*token*.stop_requested() returns*st*.stop_requested();
- [(4.5)](#task.state-4.5)
*prom*.*token*.stop_possible() returns*st*.stop_possible(); and
- [(4.6)](#task.state-4.6)
for types Fn and Init such that both[invocable](concept.invocable#concept:invocable "18.7.2Concept invocable[concept.invocable]")<Fn> and[constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<Fn, Init> are modeled,stop_token_type::callback_type<Fn> models[*stoppable-callback-for*](stoptoken.concepts#concept:stoppable-callback-for "32.3.3Stop token concepts[stoptoken.concepts]")<Fn, stop_token_type, Init>[.](#task.state-4.sentence-4)
After that invokes *handle*.resume()[.](#task.state-4.sentence-5)
#### [33.13.6.5](#task.promise) Class task::promise_type [[task.promise]](task.promise)
namespace std::execution {template<class T, class Environment>class task<T, Environment>::promise_type {public:template<class... Args> promise_type(const Args&... args);
task get_return_object() noexcept; auto initial_suspend() noexcept; auto final_suspend() noexcept; void uncaught_exception();
coroutine_handle<> unhandled_stopped(); void return_void(); // present only if is_void_v<T> is truetemplate<class V>void return_value(V&& value); // present only if is_void_v<T> is falsetemplate<class E>*unspecified* yield_value(with_error<E> error); template<class A>auto await_transform(A&& a); template<class Sch>auto await_transform(change_coroutine_scheduler<Sch> sch); *unspecified* get_env() const noexcept; template<class... Args>void* operator new(size_t size, Args&&... args); void operator delete(void* pointer, size_t size) noexcept; private:using *error-variant* = *see below*; // *exposition only* allocator_type *alloc*; // *exposition only* stop_source_type *source*; // *exposition only* stop_token_type *token*; // *exposition only* optional<T> *result*; // *exposition only*; present only if is_void_v<T> is false*error-variant* *errors*; // *exposition only*};}
[1](#task.promise-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7466)
Let *prom* be an object of promise_type and let *tsk* be the task object
created by *prom*.get_return_object()[.](#task.promise-1.sentence-1)
The description below
refers to objects *STATE*(*prom*),*RCVR*(*prom*),
and *SCHED*(*prom*) associated with *tsk* during evaluation of task::*state*<Rcvr>::start for some receiver Rcvr[.](#task.promise-1.sentence-2)
[2](#task.promise-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7478)
*error-variant* is a variant<monostate,
remove_cvref_t<E>...>, with duplicate types removed, where E... are the parameter types of the template arguments of the specialization ofexecution::completion_signatures denoted byerror_types[.](#task.promise-2.sentence-1)
[🔗](#lib:task::promise_type,constructor)
`template<class... Args>
promise_type(const Args&... args);
`
[3](#task.promise-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7491)
*Mandates*: The first parameter of type allocator_arg_t (if any) is not
the last parameter[.](#task.promise-3.sentence-1)
[4](#task.promise-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7496)
*Effects*: If Args contains an element of type allocator_arg_t then *alloc* is initialized with the corresponding next
element of args[.](#task.promise-4.sentence-1)
Otherwise, *alloc* is initialized with allocator_type()[.](#task.promise-4.sentence-2)
[🔗](#lib:get_return_object,task::promise_type)
`task get_return_object() noexcept;
`
[5](#task.promise-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7509)
*Returns*: A task object whose member *handle* iscoroutine_handle<promise_type>::from_promise(*this)[.](#task.promise-5.sentence-1)
[🔗](#lib:initial_suspend,task::promise_type)
`auto initial_suspend() noexcept;
`
[6](#task.promise-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7520)
*Returns*: An awaitable object of unspecified type ([[expr.await]](expr.await "7.6.2.4Await")) whose
member functions arrange for
- [(6.1)](#task.promise-6.1)
the calling coroutine to be suspended,
- [(6.2)](#task.promise-6.2)
the coroutine to be resumed on an execution agent of the
execution resource associated with *SCHED*(*this)[.](#task.promise-6.sentence-1)
[🔗](#lib:final_suspend,task::promise_type)
`auto final_suspend() noexcept;
`
[7](#task.promise-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7536)
*Returns*: An awaitable object of unspecified type ([[expr.await]](expr.await "7.6.2.4Await")) whose
member functions arrange for the completion of the asynchronous
operation associated with *STATE*(*this) by invoking:
- [(7.1)](#task.promise-7.1)
set_error(std::move(*RCVR*(*this)), std::move(e)) if *errors*.index() is greater than zero ande is the value held by *errors*, otherwise
- [(7.2)](#task.promise-7.2)
set_value(std::move(*RCVR*(*this))) if is_void<T> is true,
and otherwise
- [(7.3)](#task.promise-7.3)
set_value(std::move(*RCVR*(*this)), **result*)[.](#task.promise-7.sentence-1)
[🔗](#lib:yield_value,task::promise_type)
`template<class Err>
auto yield_value(with_error<Err> err);
`
[8](#task.promise-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7560)
*Mandates*: std::move(err.error) is convertible to exactly one of theset_error_t argument types of error_types[.](#task.promise-8.sentence-1)
Let *Cerr* be that type[.](#task.promise-8.sentence-2)
[9](#task.promise-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7566)
*Returns*: An awaitable object of unspecified type ([[expr.await]](expr.await "7.6.2.4Await")) whose
member functions arrange for the calling coroutine to be suspended
and then completes the asynchronous operation associated with*STATE*(*this) by invoking set_error(std::move(*RCVR*(*this)),*Cerr*(std::move(err.error)))[.](#task.promise-9.sentence-1)
[🔗](#lib:await_transform,task::promise_type)
`template<[sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]") Sender>
auto await_transform(Sender&& sndr) noexcept;
`
[10](#task.promise-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7581)
*Returns*: If [same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<inline_scheduler, scheduler_type> is true returns as_awaitable(std::forward<Sender>(sndr), *this);
otherwise returnsas_awaitable(affine_on(std::forward<Sender>(sndr), *SCHED*(*this)), *this)[.](#task.promise-10.sentence-1)
[🔗](#lib:await_transform,task::promise_type_)
`template<class Sch>
auto await_transform(change_coroutine_scheduler<Sch> sch) noexcept;
`
[11](#task.promise-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7595)
*Effects*: Equivalent to:return await_transform(just(exchange(*SCHED*(*this), scheduler_type(sch.scheduler))), *this);
[🔗](#lib:uncaught_exception,task::promise_type)
`void uncaught_exception();
`
[12](#task.promise-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7608)
*Effects*: If the signature set_error_t(exception_ptr) is not an element
of error_types, calls terminate() ([[except.terminate]](except.terminate "14.6.2The std::terminate function"))[.](#task.promise-12.sentence-1)
Otherwise, stores current_exception() into *errors*[.](#task.promise-12.sentence-2)
[🔗](#lib:unhandled_stopped,task::promise_type)
`coroutine_handle<> unhandled_stopped();
`
[13](#task.promise-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7620)
*Effects*: Completes the asynchronous operation associated with *STATE*(*this) by invoking set_stopped(std::move(*RCVR*(*this)))[.](#task.promise-13.sentence-1)
[14](#task.promise-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7626)
*Returns*: noop_coroutine()[.](#task.promise-14.sentence-1)
[🔗](#lib:get_env,task::promise_type)
`unspecified get_env() const noexcept;
`
[15](#task.promise-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7636)
*Returns*: An object env such that queries are forwarded as follows:
- [(15.1)](#task.promise-15.1)
env.query(get_scheduler) returns scheduler_type(*SCHED*(*this))[.](#task.promise-15.1.sentence-1)
- [(15.2)](#task.promise-15.2)
env.query(get_allocator) returns *alloc*[.](#task.promise-15.2.sentence-1)
- [(15.3)](#task.promise-15.3)
env.query(get_stop_token) returns *token*[.](#task.promise-15.3.sentence-1)
- [(15.4)](#task.promise-15.4)
For any other query q and arguments a... a
call to env.query(q, a...) returns*STATE*(*this)[.](#task.promise-15.4.sentence-1)
environment.query(q, a...) if this expression
is well-formed and forwarding_query(q) is well-formed and is true[.](#task.promise-15.4.sentence-2)
Otherwise env.query(q, a...) is ill-formed[.](#task.promise-15.4.sentence-3)
[🔗](#lib:operator_new,task::promise_type)
`template<class... Args>
void* operator new(size_t size, const Args&... args);
`
[16](#task.promise-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7657)
If there is no parameter with type allocator_arg_t then letalloc be allocator_type()[.](#task.promise-16.sentence-1)
Otherwise, let arg_next be the parameter
following the first allocator_arg_t parameter,
and let alloc be allocator_type(arg_next)[.](#task.promise-16.sentence-2)
Let PAlloc be allocator_traits<allocator_type>::template rebind_alloc<U>, where U is an unspecified type
whose size and alignment are both __STDCPP_DEFAULT_NEW_ALIGNMENT__[.](#task.promise-16.sentence-3)
[17](#task.promise-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7667)
*Mandates*:
- [(17.1)](#task.promise-17.1)
The first parameter of type allocator_arg_t (if any) is not the last parameter[.](#task.promise-17.1.sentence-1)
- [(17.2)](#task.promise-17.2)
allocator_type(arg_next) is a valid expression if there is a parameter
of type allocator_arg_t[.](#task.promise-17.2.sentence-1)
- [(17.3)](#task.promise-17.3)
allocator_traits<PAlloc>::pointer is a pointer type[.](#task.promise-17.3.sentence-1)
[18](#task.promise-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7676)
*Effects*: Initializes an allocator palloc of type PAlloc withalloc[.](#task.promise-18.sentence-1)
Uses palloc to allocate storage for the
smallest array of U sufficient to provide storage for a
coroutine state of size size, and unspecified additional
state necessary to ensure that operator delete can later
deallocate this memory block with an allocator equal to palloc[.](#task.promise-18.sentence-2)
[19](#task.promise-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7686)
*Returns*: A pointer to the allocated storage[.](#task.promise-19.sentence-1)
[🔗](#lib:operator_delete,task::promise_type)
`void operator delete(void* pointer, size_t size) noexcept;
`
[20](#task.promise-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7696)
*Preconditions*: pointer was returned from an invocation of the above overload
of operator new with a size argument equal to size[.](#task.promise-20.sentence-1)
[21](#task.promise-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7701)
*Effects*: Deallocates the storage pointed to by pointer using an
allocator equal to that used to allocate it[.](#task.promise-21.sentence-1)