33 Execution control library [exec]

33.13 Coroutine utilities [exec.coro.util]


33.13.1 execution​::​as_awaitable [exec.as.awaitable]

33.13.2 execution​::​with_awaitable_senders [exec.with.awaitable.senders]

33.13.3 execution​::​affine [exec.affine]

33.13.4 execution​::​inline_scheduler [exec.inline.scheduler]

33.13.5 execution​::​task_scheduler [exec.task.scheduler]

33.13.6 execution​::​task [exec.task]

33.13.6.1 task overview [task.overview]

33.13.6.2 Class template task [task.class]

33.13.6.3 task members [task.members]

33.13.6.4 Class template task​::​state [task.state]

33.13.6.5 Class task​::​promise_type [task.promise]


33.13.1 execution​::​as_awaitable [exec.as.awaitable]

as_awaitable transforms an object into one that is awaitable within a particular coroutine.
Subclause [exec.coro.util] makes use of the following exposition-only entities: namespace std::execution { template<class Sndr, class Promise> concept awaitable-sender = single-sender<Sndr, env_of_t<Promise>> && sender-to<Sndr, typename sender-awaitable<Sndr, Promise>::awaitable-receiver> && // see below requires (Promise& p) { { p.unhandled_stopped() } -> convertible_to<coroutine_handle<>>; }; template<class Sndr> concept has-queryable-await-completion-adaptor = // exposition only sender<Sndr> && requires(Sndr&& sender) { get_await_completion_adaptor(get_env(sender)); }; template<class Sndr, class Promise> class sender-awaitable; // exposition only }
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(); }; }
awaitable-receiver is equivalent to: struct awaitable-receiver { using receiver_concept = receiver_tag; variant<monostate, result-type, exception_ptr>* result-ptr; // exposition only coroutine_handle<Promise> continuation; // exposition only // see below };
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.
Let MAKE-NOEXCEPT(expr) for some subexpression expr be expression-equivalent to [&] noexcept -> decltype(auto) { return (expr); }().
Then:
  • 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()); } MAKE-NOEXCEPT(rcvr.continuation.resume());
    Mandates: constructible_from<result-type, decltype((vs))...> is satisfied.
  • The expression set_error(rcvr, err) is equivalent to: try { rcvr.result-ptr->template emplace<2>(AS-EXCEPT-PTR(err)); // see [exec.general] } catch(...) { rcvr.result-ptr->template emplace<2>(current_exception()); } MAKE-NOEXCEPT(rcvr.continuation.resume());
  • The expression set_stopped(rcvr) is equivalent to: MAKE-NOEXCEPT( static_cast<coroutine_handle<>>( rcvr.continuation.promise().unhandled_stopped()).resume());
  • For any expression tag whose type satisfies forwarding-query and for any pack of subexpressions as, get_env(crcvr).query(tag, as...) is expression-equivalent to: tag(get_env(as_const(MAKE-NOEXCEPT(crcvr.continuation.promise()))), as...)
sender-awaitable(Sndr&& sndr, Promise& p);
Effects: Initializes state with connect(std::forward<Sndr>(sndr), awaitable-receiver{addressof(result), coroutine_handle<Promise>::from_promise(p)})
value-type await_resume();
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));
as_awaitable is a customization point object.
For subexpressions expr and p where p is an lvalue, Expr names the type decltype((expr)) and Promise 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:
  • expr.as_awaitable(p) if that expression is well-formed.
    Mandates: is-awaitable<A, Promise> is true, where A is the type of the expression above.
  • Otherwise, adapt-for-await-completion(transform_sender(expr, get_env(p))).as_awaitable(p) if this expression is well-formed, sender_in<Expr, env_of_t<Promise>> is true, and single-sender-value-type<Expr, env_of_t<Promise>> is well-formed, except that p is only evaluated once.
  • Otherwise, (void(p), expr) if decltype(GET-AWAITER(expr)) satisfies is-awaiter<Promise>.
  • Otherwise, sender-awaitable{adapt-for-await-completion(transform_sender(expr, get_env(p))), p} if sender_in<Expr, env_of_t<Promise>> is true and single-sender-value-type<Expr, env_of_t<Promise>> is well-formed, except that p is only evaluated once.
  • Otherwise, (void(p), expr).
adapt-for-await-completion(s) is expression-equivalent to
  • get_await_completion_adaptor(get_env(s))(s) if that is well-formed, except that s is evaluated only once,
  • otherwise, s.

33.13.2 execution​::​with_awaitable_senders [exec.with.awaitable.senders]

with_awaitable_senders, when used as the base class of a coroutine promise type, makes senders awaitable in that coroutine type.
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.
[Note 1: 
The coroutine is never resumed, and the unhandled_stopped of the coroutine caller's promise type is called.
— end note]
namespace std::execution { template<class-type Promise> struct with_awaitable_senders { template<class OtherPromise> requires (!same_as<OtherPromise, void>) void set_continuation(coroutine_handle<OtherPromise> h) noexcept; coroutine_handle<> continuation() const noexcept { return continuation; } coroutine_handle<> unhandled_stopped() 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; }; }
template<class OtherPromise> requires (!same_as<OtherPromise, void>) void set_continuation(coroutine_handle<OtherPromise> h) noexcept;
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; }
template<class Value> call-result-t<as_awaitable_t, Value, Promise&> await_transform(Value&& value);
Effects: Equivalent to: return as_awaitable(std::forward<Value>(value), static_cast<Promise&>(*this));

33.13.3 execution​::​affine [exec.affine]

affine adapts a sender into one that completes on the receiver's scheduler.
If the algorithm determines that the adapted sender already completes on the correct scheduler it can avoid any scheduling operation.
The name affine denotes a pipeable sender adaptor object.
For a subexpression sndr, if decltype((​sndr)) does not satisfy sender, affine(sndr) is ill-formed.
Otherwise, the expression affine(sndr) is expression-equivalent to make-sender(affine, env<>(), sndr).
For a subexpression sch whose type models scheduler, let UNSTOPPABLE-SCHEDULER(sch) be an expression e whose type models scheduler such that:
  • schedule(e) is expression-equivalent to unstoppable(schedule(sch)).
  • For any query object q and pack of subexpressions args..., e.query(q, args...) is expression-equivalent to sch.query(q, args...).
  • The expression e == UNSTOPPABLE-SCHEDULER(other) is expression-equivalent to sch == other.
Let sndr and ev be subexpressions such that Sndr is decltype((sndr)).
If sender-for<Sndr, affine_t> is false, then the expression affine.transform_sender(sndr, ev) is ill-formed; otherwise, it is equal to: auto& [_, _, child] = sndr; if constexpr (requires { std::forward_like<Sndr>(child).affine(); }) { return std::forward_like<Sndr>(child).affine(); } else { return continues_on(std::forward_like<Sndr>(child), UNSTOPPABLE-SCHEDULER(get_start_scheduler(ev))); }
Recommended practice: Implementations should provide affine member functions for senders that are known to resume on the scheduler where they were started.
Example senders for which that is the case are just, just_error, just_stopped, read_env, and write_env.
Let out_sndr be a subexpression denoting a sender returned from affine(sndr) or one equal to such, and let OutSndr be the type decltype((out_sndr)).
Let out_rcvr be a subexpression denoting a receiver that has an environment of type Env.
If get_start_scheduler(get_env(out_rcvr)) is ill-formed or does not satisfy infallible-scheduler<Env>, then evaluation of the expression get_completion_signatures<OutSndr, Env>() exits with an exception.
Let op be an lvalue referring to the operation state that results from connecting out_sndr to out_rcvr.
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 with sch.
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.

33.13.4 execution​::​inline_scheduler [exec.inline.scheduler]

namespace std::execution { class inline_scheduler { class inline-sender; // exposition only template<receiver R> class inline-state; // exposition only public: using scheduler_concept = scheduler_tag; constexpr inline-sender schedule() noexcept { return {}; } constexpr bool operator==(const inline_scheduler&) const noexcept = default; }; }
inline_scheduler is a class that models scheduler ([exec.sched]).
All objects of type inline_scheduler are equal.
For a subexpression sch of type inline_scheduler, a query object q, and a pack of subexpressions args, the expression sch.query(q, args...) is expression-equivalent to inline-attrs<set_value_t>().query(q, args...).
inline-sender is an exposition-only type that satisfies sender.
The type completion_signatures_of_t<inline-sender> is completion_signatures<set_value_t()>.
Let sndr be an expression of type inline-sender, let rcvr be an expression such that receiver-of<decltype((rcvr)), CS> is true where CS is completion_signatures<set_value_t()>, then 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.
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:
  • the object to which REC(o) refers remains valid for the lifetime of the object to which o refers, and
  • the expression start(o) is equivalent to set_value(std​::​move(REC(o))).

33.13.5 execution​::​task_scheduler [exec.task.scheduler]

namespace std::execution { class task_scheduler { class ts-domain; // exposition only template<scheduler Sch> class backend-for; // exposition only public: using scheduler_concept = scheduler_tag; template<class Sch, class Allocator = allocator<void>> requires (!same_as<task_scheduler, remove_cvref_t<Sch>>) && scheduler<Sch> explicit task_scheduler(Sch&& sch, Allocator alloc = {}); task_scheduler(const task_scheduler&) = default; task_scheduler& operator=(const task_scheduler&) = default; see below schedule(); friend bool operator==(const task_scheduler& lhs, const task_scheduler& rhs) noexcept; template<class Sch> requires (!same_as<task_scheduler, Sch>) && scheduler<Sch> friend bool operator==(const task_scheduler& lhs, const Sch& rhs) noexcept; private: // see [exec.parschedrepl.psb] shared_ptr<parallel_scheduler_replacement::parallel_scheduler_backend> sch_; // exposition only }; }
task_scheduler is a class that models scheduler ([exec.sched]).
Given an object s of type task_scheduler, let SCHED(s) be the object pointed to by the pointer owned by s.sch_.
The expression get_forward_progress_guarantee(s) is equivalent to get_forward_progress_guarantee(SCHED(s)).
The expression get_completion_domain<set_value_t>(s) is equivalent to task_scheduler​::​ts-domain().
template<class Sch, class Allocator = allocator<void>> requires(!same_as<task_scheduler, remove_cvref_t<Sch>>) && scheduler<Sch> explicit task_scheduler(Sch&& sch, Allocator alloc = {});
Mandates: Sch satisfies infallible-scheduler<env<>>.
Effects: Initializes sch_ with: allocate_shared<backend-for<remove_cvref_t<Sch>>>(alloc, std::forward<Sch>(sch))
Recommended practice: Implementations should avoid the use of dynamically allocated memory for small scheduler objects.
Remarks: Any allocations performed by calls on *this are performed using a copy of alloc.
bool operator==(const task_scheduler& lhs, const task_scheduler& rhs) noexcept;
Effects: Equivalent to: return lhs == SCHED(rhs);
template<class Sch> requires (!same_as<task_scheduler, Sch>) && scheduler<Sch> bool operator==(const task_scheduler& lhs, const Sch& rhs) noexcept;
Returns: false if the type of SCHED(lhs) is not Sch, otherwise SCHED(lhs) == rhs.
For an lvalue r of a type derived from receiver_proxy, let WRAP-RCVR(r) be an object of a type that models receiver and whose completion handlers result in invoking the corresponding completion handlers of r.
namespace std::execution { template<scheduler Sch> class task_scheduler::backend-for : public parallel_scheduler_replacement::parallel_scheduler_backend { // exposition only public: explicit backend-for(Sch sch) : sched_(std::move(sch)) {} void schedule(receiver_proxy& r, span<byte> s) noexcept override; void schedule_bulk_chunked(size_t shape, bulk_item_receiver_proxy& r, span<byte> s) noexcept override; void schedule_bulk_unchunked(size_t shape, bulk_item_receiver_proxy& r, span<byte> s) noexcept override; private: Sch sched_; }; }
Let env be a pack of subexpressions, and let just-sndr-like be a sender whose only value completion signature is set_value_t() and for which the expression get_completion_scheduler<set_value_t>(get_env(just-sndr-like), env...) is expression-equivalent to get_completion_scheduler<set_value_t>(sched_, env...).
void schedule(receiver_proxy& r, span<byte> s) noexcept override;
Effects: Constructs an operation state os with connect(schedule(sched_), WRAP-RCVR(r)) and calls start(os).
void schedule_bulk_chunked(size_t shape, bulk_item_receiver_proxy& r, span<byte> s) noexcept override;
Effects: Let chunk_size be an integer less than or equal to shape, let num_chunks be (shape + chunk_size - 1) / chunk_size, and let fn be a function object such that for an integer i, fn(i) calls r.execute(i * chunk_size, m), where m is the lesser of (i + 1) * chunk_size and shape.
Constructs an operation state os as if with connect(bulk(just-sndr-like, par, num_chunks, fn), WRAP-RCVR(r)) and calls start(os).
void schedule_bulk_unchunked(size_t shape, bulk_item_receiver_proxy& r, span<byte> s) noexcept override;
Effects: Let fn be a function object such that for an integer i, fn(i) is equivalent to r.execute(i, i + 1).
Constructs an operation state os as if with connect(bulk(just-sndr-like, par, shape, fn), WRAP-RCVR(r)) and calls start(os).
see below schedule();
Returns: A prvalue ts-sndr whose type models sender such that:
  • get_completion_scheduler<set_value_t>(get_env(ts-sndr)) is equal to *this.
  • get_completion_domain<set_value_t>(get_env(ts-sndr)) is expression-equivalent to ts-domain().
  • If a receiver rcvr is connected to ts-sndr and the resulting operation state is started, calls sch_->schedule(r, s), where
  • For any type E, completion_signatures_of_t<decltype(ts-sndr), E> denotes completion_signatures<set_value_t()> if unstoppable_token<stop_token_of_t<E>> is true, and otherwise completion_signatures<set_value_t(), set_stopped_t()>.
namespace std::execution { class task_scheduler::ts-domain : public default_domain { // exposition only public: template<class BulkSndr, class Env> static constexpr auto transform_sender(set_value_t, BulkSndr&& bulk_sndr, const Env& env) noexcept(see below); }; }
template<class BulkSndr, class Env> static constexpr auto transform_sender(BulkSndr&& bulk_sndr, const Env& env) noexcept(is_nothrow_constructible_v<decay_t<BulkSndr>, BulkSndr>);
Constraints:
Effects: Equivalent to: auto& [_, data, child] = bulk_sndr; auto& [_, shape, fn] = data; auto sch = call-with-default(get_completion_scheduler<set_value_t>, not-a-scheduler(), get_env(child), FWD-ENV(env)); return e; where e is not-a-sender() if the type of sch is not task_scheduler; otherwise, it is a prvalue whose type models sender such that, if it is connected to a receiver rcvr and the resulting operation state is started, child is connected to an unspecified receiver R and started.
The expression get_env(R) is expression-equivalent to FWD-ENV(get_env(rcvr-copy)), where rcvr-copy is an lvalue subexpression designating an object decay-copied from rcvr.
If child completes with an error or a stopped completion, the completion operation is forwarded unchanged to rcvr.
Otherwise, let args be a pack of lvalue subexpressions designating objects decay-copied from the value result datums.
Then:
  • If bulk_sndr was the result of the evaluation of an expression equivalent to bulk_chunked(child, policy, shape, fn) or a copy of such, then sch_->schedule_bulk_chunked(shape, r, s) is called where r is a bulk chunked proxy ([exec.par.scheduler]) for rcvr with callable fn and arguments args, and s is a preallocated backend storage for r.
  • Otherwise, calls sch_->schedule_bulk_unchunked(shape, r, s) where r is a bulk unchunked proxy for rcvr with callable fn and arguments args, and s is a preallocated backend storage for r.

33.13.6 execution​::​task [exec.task]

33.13.6.1 task overview [task.overview]

The task class template represents a sender that can be used as the return type of coroutines.
The first template parameter T defines the type of the value completion datum ([exec.async.ops]) if T is not void.
Otherwise, there are no value completion datums.
Inside coroutines returning task<T, E> the operand of co_return (if any) becomes the argument of set_value.
The second template parameter Environment is used to customize the behavior of task.

33.13.6.2 Class template task [task.class]

namespace std::execution { template<class T = void, class Environment = env<>> class task { // [task.state] template<receiver Rcvr> class state; // exposition only public: using sender_concept = sender_tag; using allocator_type = see below; using start_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] class promise_type; task(task&&) noexcept; ~task(); template<class Self, class... Env> static consteval auto get_completion_signatures(); template<receiver Rcvr> state<Rcvr> connect(Rcvr&& rcvr) &&; private: coroutine_handle<promise_type> handle; // exposition only }; }
task<T, E> models sender ([exec.snd]) if T is void, a reference type, or a cv-unqualified non-array object type and E is a class type.
Otherwise a program that instantiates the definition of task<T, E> is ill-formed.
The nested types of task template specializations are determined based on the Environment parameter:
  • allocator_type is Environment​::​allocator_type if that qualified-id is valid and denotes a type, allocator<byte> otherwise.
  • start_scheduler_type is Environment​::​start_scheduler_type if that qualified-id is valid and denotes a type, task_scheduler otherwise.
  • stop_source_type is Environment​::​stop_source_type if that qualified-id is valid and denotes a type, inplace_stop_source otherwise.
  • error_types is Environment​::​error_types if that qualified-id is valid and denotes a type, completion_signatures<set_error_t(exception_ptr)> otherwise.
A program is ill-formed if error_types is not a specialization of execution​::​completion_signatures or if the template arguments of that specialization contain an element which is not of the form set_error_t(E) for some type E.
allocator_type shall meet the Cpp17Allocator requirements, scheduler_type shall model scheduler, and stop_source_type shall model stoppable-source.

33.13.6.3 task members [task.members]

task(task&& other) noexcept;
Effects: Initializes handle with exchange(other.handle, {}).
~task();
Effects: Equivalent to: if (handle) handle.destroy();
template<class Self, class... Env> static consteval auto get_completion_signatures();
Let the type C be a specialization of execution​::​completion_signatures with the template arguments (in unspecified order):
  • set_value_t() if T is void, and set_value_t(T) otherwise;
  • template arguments of the specialization of execution​::​completion_signatures denoted by error_types; and
  • set_stopped_t().
Returns: C().
template<receiver Rcvr> state<Rcvr> connect(Rcvr&& recv) &&;
Mandates: At least one of the expressions allocator_type(get_allocator(get_env(rcvr))) and allocator_type() is well-formed.
Preconditions: bool(handle) is true.
Effects: Equivalent to: return state<Rcvr>(exchange(handle, {}), std::forward<Rcvr>(recv));

33.13.6.4 Class template task​::​state [task.state]

namespace std::execution { template<class T, class Environment> template<receiver Rcvr> class task<T, Environment>::state { // exposition only public: using operation_state_concept = operation_state_tag; template<class R> state(coroutine_handle<promise_type> h, R&& rr); ~state(); void start() & noexcept; stop_token_type get-stop-token(); // exposition only private: using own-env-t = see below; // exposition only coroutine_handle<promise_type> handle; // exposition only remove_cvref_t<Rcvr> rcvr; // exposition only optional<stop_source_type> source; // exposition only own-env-t own-env; // exposition only Environment environment; // exposition only optional<T> result; // exposition only; present only if is_void_v<T> is false exception_ptr error; // exposition only }; }
The type own-env-t is Environment​::​template env_type<decltype(get_env(​declval​<Rcvr>()))> if that qualified-id is valid and denotes a type, env<> otherwise.
template<class R> state(coroutine_handle<promise_type> h, R&& rr);
Effects: Initializes
  • handle with std​::​move(h);
  • rcvr with std​::​forward<R>(rr);
  • own-env with own-env-t(get_env(rcvr)) if that expression is valid and own-env-t() otherwise.
    If neither of these expressions is valid, the program is ill-formed.
  • environment with Environment(own-env) if that expression is valid, otherwise Environment(​get_env(rcvr)) if this expression is valid, otherwise Environment().
    If neither of these expressions is valid, the program is ill-formed.
~state();
Effects: Equivalent to: if (handle) handle.destroy();
void start() & noexcept;
Effects: Let prom be the object handle.promise().
Associates STATE(prom), RCVR(prom), and SCHED(prom) with *this as follows:
  • STATE(prom) is *this.
  • RCVR(prom) is rcvr.
  • SCHED(prom) is the object initialized with start_scheduler_type(get_start_scheduler(get_env(rcvr))) if that expression is valid and start_scheduler_type() otherwise.
    If neither of these expressions is valid, the program is ill-formed.
Finally, invokes handle.resume().
stop_token_type get-stop-token(); // exposition only
Effects: If same_as<decltype(declval<stop_source_type>().get_token()), decltype(get_
stop_token(get_env(rcvr)))>
is true, returns get_stop_token(get_env(rcvr)).
Otherwise, if source.has_value() is false, initializes the contained value of source such that
  • source->stop_requested() returns get_stop_token(get_env(rcvr))->stop_requested();
    and
  • source->stop_possible() returns get_stop_token(get_env(rcvr))->stop_possible().
Finally, returns source->get_token().

33.13.6.5 Class task​::​promise_type [task.promise]

namespace std::execution { template<class T, class Environment> class task<T, Environment>::promise_type { public: task get_return_object() noexcept; static constexpr suspend_always initial_suspend() noexcept { return {}; } auto final_suspend() noexcept; void unhandled_exception(); coroutine_handle<> unhandled_stopped() noexcept; void return_void(); // present only if is_void_v<T> is true template<class V = T> void return_value(V&& value); // present only if is_void_v<T> is false template<class E> unspecified yield_value(with_error<E> error); template<sender Sender> auto await_transform(Sender&& sndr); unspecified get_env() const noexcept; void* operator new(size_t size); template<class Alloc, class... Args> void* operator new(size_t size, allocator_arg_t, Alloc alloc, Args&&...); template<class This, class Alloc, class... Args> void* operator new(size_t size, const This&, allocator_arg_t, Alloc alloc, Args&&...); void operator delete(void* pointer, size_t size) noexcept; }; }
Let prom be an object of promise_type and let tsk be the task object created by prom.get_return_object().
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 get_return_object() noexcept;
Returns: A task object whose member handle is coroutine_handle<promise_type>​::​​from_promise​(*this).
auto final_suspend() noexcept;
Returns: An awaitable object of unspecified type ([expr.await]) whose member functions arrange for the completion of the asynchronous operation associated with STATE(*this).
Let st be a reference to STATE(*this).
The asynchronous completion first destroys the coroutine frame using st.handle.destroy() and then invokes:
  • set_error(std​::​move(st.rcvr), std​::​move(st.error)) if bool(st.error) is true, otherwise
  • set_value(std​::​move(st.rcvr)) if is_void_v<T> is true, and otherwise
  • set_value(std​::​move(st.rcvr), *std​::​move(st.result)).
template<class Err> auto yield_value(with_error<Err> err);
Mandates: std​::​move(err.error) is convertible to exactly one of the set_error_t argument types of error_types.
Let Cerr be that type.
Returns: An awaitable object of unspecified type ([expr.await]) whose member functions arrange for the calling coroutine to be suspended and then completes the asynchronous operation associated with STATE(*this).
Let st be a reference to STATE(*this).
Then the asynchronous operation completes by first destroying the coroutine frame using st.handle.destroy() and then invoking set_error(std​::​move(st.rcvr), Cerr(std​::​move(err.error))).
template<sender Sender> auto await_transform(Sender&& sndr);
Returns: If same_as<inline_scheduler, start_scheduler_type> is true, returns as_awaitable(​std​::​forward<Sender>(sndr), *this); otherwise returns as_awaitable(affine(std​::​forward<​Sender>(sndr)), *this).
void unhandled_exception();
Effects: If the signature set_error_t(exception_ptr) is not an element of error_types, calls terminate() ([except.terminate]).
Otherwise, stores current_exception() into STATE(*this).error.
coroutine_handle<> unhandled_stopped() noexcept;
Effects: Completes the asynchronous operation associated with STATE(*this).
Let st be a reference to STATE(*this).
The asynchronous operation is completed by first destroying the coroutine frame using st.handle.destroy() and then invoking set_stopped(std​::​move(st.rcvr)).
Returns: noop_coroutine().
void return_void();
Effects: Does nothing.
template<class V> void return_value(V&& v);
Effects: Equivalent to result.emplace(std​::​forward<V>(v)).
unspecified get_env() const noexcept;
Returns: An object env such that queries are forwarded as follows:
  • env.query(get_start_scheduler) returns start_scheduler_type(SCHED(*this)).
  • env.query(get_allocator) returns allocator_type(get_allocator(get_env(RCVR(*this)))) if this expression is well-formed and allocator_type() otherwise.
  • env.query(get_stop_token) returns STATE(*this).get-stop-token().
  • For any other query q and arguments a... a call to env.query(q, a...) returns STATE(*this).
    environment.query(q, a...) if this expression is well-formed and forwarding_query(q) is well-formed and is true.
    Otherwise env.query(q, a...) is ill-formed.
void* operator new(size_t size);
Effects: Equivalent to: return operator new(size, allocator_arg, allocator_type());
template<class Alloc, class... Args> void* operator new(size_t size, allocator_arg_t, Alloc alloc, Args&&...); template<class This, class Alloc, class... Args> void* operator new(size_t size, const This&, allocator_arg_t, Alloc alloc, Args&&...);
Let PAlloc be allocator_traits<Alloc>​::​template rebind_alloc<U>, where U is an unspecified type whose size and alignment are both __STDCPP_DEFAULT_NEW_ALIGNMENT__.
Mandates: allocator_traits<PAlloc>​::​pointer is a pointer type.
Effects: Initializes an allocator palloc of type PAlloc with alloc.
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.
Returns: A pointer to the allocated storage.
void operator delete(void* pointer, size_t size) noexcept;
Preconditions: pointer was returned from an invocation of the above overload of operator new with a size argument equal to size.
Effects: Deallocates the storage pointed to by pointer using an allocator equal to that used to allocate it.