33 Execution control library [exec]

33.9 Senders [exec.snd]

33.9.4 Awaitable helpers [exec.awaitable]

The sender concepts recognize awaitables as senders.
For [exec], an awaitable is an expression that would be well-formed as the operand of a co_await expression within a given context.
For a subexpression c, let GET-AWAITER(c, p) be expression-equivalent to the series of transformations and conversions applied to c as the operand of an await-expression in a coroutine, resulting in lvalue e as described by [expr.await], where p is an lvalue referring to the coroutine's promise, which has type Promise.
[Note 1: 
This includes the invocation of the promise type's await_transform member if any, the invocation of the operator co_await picked by overload resolution if any, and any necessary implicit conversions and materializations.
— end note]
Let is-awaitable be the following exposition-only concept: namespace std { template<class T> concept await-suspend-result = see below; // exposition only template<class A, class Promise> concept is-awaiter = // exposition only requires (A& a, coroutine_handle<Promise> h) { a.await_ready() ? 1 : 0; { a.await_suspend(h) } -> await-suspend-result; a.await_resume(); }; template<class C, class Promise> concept is-awaitable = // exposition only requires (C (*fc)() noexcept, Promise& p) { { GET-AWAITER(fc(), p) } -> is-awaiter<Promise>; }; }
await-suspend-result<T> is true if and only if one of the following is true:
  • T is void, or
  • T is bool, or
  • T is a specialization of coroutine_handle.
For a subexpression c such that decltype((c)) is type C, and an lvalue p of type Promise, await-result-
type
<C, Promise>
denotes the type decltype(GET-AWAITER(c, p).await_resume()).
Let with-await-transform be the exposition-only class template: namespace std::execution { template<class T, class Promise> concept has-as-awaitable = // exposition only requires (T&& t, Promise& p) { { std::forward<T>(t).as_awaitable(p) } -> is-awaitable<Promise&>; }; template<class Derived> struct with-await-transform { // exposition only template<class T> T&& await_transform(T&& value) noexcept { return std::forward<T>(value); } template<has-as-awaitable<Derived> T> decltype(auto) await_transform(T&& value) noexcept(noexcept(std::forward<T>(value).as_awaitable(declval<Derived&>()))) { return std::forward<T>(value).as_awaitable(static_cast<Derived&>(*this)); } }; }
Let env-promise be the exposition-only class template: namespace std::execution { template<class Env> struct env-promise : with-await-transform<env-promise<Env>> { // exposition only unspecified get_return_object() noexcept; unspecified initial_suspend() noexcept; unspecified final_suspend() noexcept; void unhandled_exception() noexcept; void return_void() noexcept; coroutine_handle<> unhandled_stopped() noexcept; const Env& get_env() const noexcept; }; }
[Note 2: 
Specializations of env-promise are used only for the purpose of type computation; its members need not be defined.
— end note]