33 Execution control library [exec]

33.13 Coroutine utilities [exec.coro.util]

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.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.
HTTPS Β· eel.is
← Home