Files
cppdraft_translate/cppdraft/exec/when/all.md
2025-10-25 03:02:53 +03:00

242 lines
13 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[exec.when.all]
# 33 Execution control library [[exec]](./#exec)
## 33.9 Senders [[exec.snd]](exec.snd#exec.when.all)
### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#exec.when.all)
#### 33.9.12.12 execution::when_all [exec.when.all]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4368)
when_all and when_all_with_variant both adapt multiple input senders into a sender
that completes when all input senders have completed[.](#1.sentence-1)
when_all only accepts senders
with a single value completion signature and
on success concatenates all the input senders' value result datums
into its own value completion operation[.](#1.sentence-2)
when_all_with_variant(sndrs...) is semantically equivalent to
when_all(into_variant(sndrs)...),
where sndrs is a pack of subexpressions
whose types model [sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]")[.](#1.sentence-3)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4381)
The names when_all and when_all_with_variant denote
customization point objects[.](#2.sentence-1)
Let sndrs be a pack of subexpressions,
let Sndrs be a pack of the types decltype((sndrs))..., and
let CD be
the type common_type_t<decltype(*get-domain-early*(sndrs))...>[.](#2.sentence-2)
Let CD2 be CD if CD is well-formed, anddefault_domain otherwise[.](#2.sentence-3)
The expressions when_all(sndrs...) andwhen_all_with_variant(sndrs...) are ill-formed
if any of the following is true:
- [(2.1)](#2.1)
sizeof...(sndrs) is 0, or
- [(2.2)](#2.2)
([sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]")<Sndrs> && ...) is false[.](#2.sentence-4)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4400)
The expression when_all(sndrs...) is expression-equivalent to:transform_sender(CD2(), *make-sender*(when_all, {}, sndrs...))
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4406)
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2Exposition-only entities"))
is specialized for when_all_t as follows:
[🔗](#lib:impls-for%3cwhen_all_t%3e)
namespace std::execution {template<>struct *impls-for*<when_all_t> : *default-impls* {static constexpr auto *get-attrs* = *see below*; static constexpr auto *get-env* = *see below*; static constexpr auto *get-state* = *see below*; static constexpr auto *start* = *see below*; static constexpr auto *complete* = *see below*; template<class Sndr, class... Env>static consteval void *check-types*(); };}
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4426)
Let *make-when-all-env* be
the following exposition-only function template:template<class Env>constexpr auto *make-when-all-env*(inplace_stop_source& stop_src, // *exposition only* Env&& env) noexcept {return *see below*;}
Returns an object e such that
- [(5.1)](#5.1)
decltype(e) models [*queryable*](exec.queryable.concept#concept:queryable "33.2.2queryable concept[exec.queryable.concept]"), and
- [(5.2)](#5.2)
e.query(get_stop_token) is expression-equivalent tostate.*stop-src*.get_token(), and
- [(5.3)](#5.3)
given a query object q with type other than cv stop_token_t and
whose type satisfies *forwarding-query*,e.query(q) is expression-equivalent to get_env(rcvr).query(q)[.](#5.sentence-2)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4452)
Let *when-all-env* be an alias template such that*when-all-env*<Env> denotes the typedecltype(*make-
when-all-env*(declval<inplace_stop_source&>(), declval<Env>()))[.](#6.sentence-1)
[🔗](#lib:check-types,impls-for%3cwhen_all_t%3e)
`template<class Sndr, class... Env>
static consteval void check-types();
`
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4464)
Let Is be the pack of integral template arguments of
the integer_sequence specialization denoted by*indices-for*<Sndr>[.](#7.sentence-1)
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4469)
*Effects*: Equivalent to:auto fn = []<class Child>() {auto cs = get_completion_signatures<Child, *when-all-env*<Env>...>(); if constexpr (cs.*count-of*(set_value) >= 2)throw *unspecified-exception*(); *decay-copyable-result-datums*(cs); // see [[exec.snd.expos]](exec.snd.expos "33.9.2Exposition-only entities")};(fn.template operator()<*child-type*<Sndr, Is>>(), ...); where *unspecified-exception* is
a type derived from exception[.](#8.sentence-1)
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4484)
*Throws*: Any exception thrown as a result of evaluating the *Effects*, or
an exception of an unspecified type
derived from exception when CD is ill-formed[.](#9.sentence-1)
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4491)
The member *impls-for*<when_all_t>::*get-attrs* is initialized with a callable object
equivalent to the following lambda expression:[](auto&&, auto&&... child) noexcept {if constexpr ([same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<CD, default_domain>) {return env<>(); } else {return *MAKE-ENV*(get_domain, CD()); }}
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4505)
The member *impls-for*<when_all_t>::*get-env* is initialized with a callable object
equivalent to the following lambda expression:[]<class State, class Rcvr>(auto&&, State& state, const Receiver& rcvr) noexcept {return *make-when-all-env*(state.*stop-src*, get_env(rcvr));}
[12](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4515)
The member *impls-for*<when_all_t>::*get-state* is initialized with a callable object
equivalent to the following lambda expression:[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) noexcept(noexcept(e)) -> decltype(e) {return e;} where e is the expressionstd::forward<Sndr>(sndr).*apply*(*make-state*<Rcvr>()) and where *make-state* is the following exposition-only class template:enum class *disposition* { *started*, *error*, *stopped* }; // *exposition only*template<class Rcvr>struct *make-state* {template<class... Sndrs>auto operator()(auto, auto, Sndrs&&... sndrs) const {using values_tuple = *see below*; using errors_variant = *see below*; using stop_callback = stop_callback_for_t<stop_token_of_t<env_of_t<Rcvr>>, *on-stop-request*>; struct *state-type* {void *arrive*(Rcvr& rcvr) noexcept { // *exposition only*if (0 == --count) {*complete*(rcvr); }}void *complete*(Rcvr& rcvr) noexcept; // *exposition only* atomic<size_t> *count*{sizeof...(sndrs)}; // *exposition only* inplace_stop_source *stop_src*{}; // *exposition only* atomic<*disposition*> disp{*disposition*::*started*}; // *exposition only* errors_variant *errors*{}; // *exposition only* values_tuple *values*{}; // *exposition only* optional<stop_callback> *on_stop*{nullopt}; // *exposition only*}; return *state-type*{}; }};
[13](#13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4562)
Let *copy-fail* be exception_ptr if decay-copying any of the child senders' result datums can potentially throw;
otherwise, *none-such*,
where *none-such* is an unspecified empty class type[.](#13.sentence-1)
[14](#14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4568)
The alias values_tuple denotes the typetuple<value_types_of_t<Sndrs, *FWD-ENV-T*(env_of_t<Rcvr>), *decayed-tuple*, optional>...> if that type is well-formed; otherwise, tuple<>[.](#14.sentence-1)
[15](#15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4575)
The alias errors_variant denotes
the type variant<*none-such*, *copy-fail*, Es...> with duplicate types removed,
where Es is the pack of the decayed types
of all the child senders' possible error result datums[.](#15.sentence-1)
[16](#16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4582)
The membervoid *state-type*::*complete*(Rcvr& rcvr) noexcept behaves as follows:
- [(16.1)](#16.1)
If disp is equal to *disposition*::*started*,
evaluates:auto tie = []<class... T>(tuple<T...>& t) noexcept { return tuple<T&...>(t); };auto set = [&](auto&... t) noexcept { set_value(std::move(rcvr), std::move(t)...); };
*on_stop*.reset();
apply([&](auto&... opts) noexcept { apply(set, tuple_cat(tie(*opts)...)); },
values);
- [(16.2)](#16.2)
Otherwise,
if disp is equal to *disposition*::*error*,
evaluates:*on_stop*.reset();
visit([&]<class Error>(Error& error) noexcept {if constexpr (![same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<Error, *none-such*>) { set_error(std::move(rcvr), std::move(error)); }},
errors);
- [(16.3)](#16.3)
Otherwise, evaluates:*on_stop*.reset();
set_stopped(std::move(rcvr));
[17](#17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4623)
The member *impls-for*<when_all_t>::*start* is initialized with a callable object
equivalent to the following lambda expression:[]<class State, class Rcvr, class... Ops>( State& state, Rcvr& rcvr, Ops&... ops) noexcept -> void { state.*on_stop*.emplace( get_stop_token(get_env(rcvr)), *on-stop-request*{state.*stop_src*}); if (state.*stop_src*.stop_requested()) { state.*on_stop.*reset();
set_stopped(std::move(rcvr)); } else {(start(ops), ...); }}
[18](#18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4642)
The member *impls-for<when_all_t>::*complete** is initialized with a callable object
equivalent to the following lambda expression:[]<class Index, class State, class Rcvr, class Set, class... Args>(this auto& complete, Index, State& state, Rcvr& rcvr, Set, Args&&... args) noexcept -> void {if constexpr ([same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<Set, set_error_t>) {if (*disposition*::*error* != state.disp.exchange(*disposition*::*error*)) { state.*stop_src*.request_stop(); *TRY-EMPLACE-ERROR*(state.errors, std::forward<Args>(args)...); }} else if constexpr ([same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<Set, set_stopped_t>) {auto expected = *disposition*::*started*; if (state.disp.compare_exchange_strong(expected, *disposition*::*stopped*)) { state.*stop_src*.request_stop(); }} else if constexpr (![same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<decltype(State::values), tuple<>>) {if (state.disp == *disposition*::*started*) {auto& opt = get<Index::value>(state.values); *TRY-EMPLACE-VALUE*(complete, opt, std::forward<Args>(args)...); }} state.*arrive*(rcvr);} where *TRY-EMPLACE-ERROR*(v, e),
for subexpressions v and e, is equivalent to:try { v.template emplace<decltype(auto(e))>(e);} catch (...) { v.template emplace<exception_ptr>(current_exception());} if the expression decltype(auto(e))(e) is potentially throwing;
otherwise, v.template emplace<decltype(auto(e))>(e);
and where *TRY-EMPLACE-VALUE*(c, o, as...),
for subexpressions c, o, and pack of subexpressions as,
is equivalent to:try { o.emplace(as...);} catch (...) { c(Index(), state, rcvr, set_error, current_exception()); return;} if the expression *decayed-tuple*<decltype(as)...>{as...} is potentially throwing;
otherwise, o.emplace(as...)[.](#18.sentence-1)
[19](#19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4694)
The expression when_all_with_variant(sndrs...) is expression-equivalent to:transform_sender(CD2(), *make-sender*(when_all_with_variant, {}, sndrs...));
[20](#20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4701)
Given subexpressions sndr and env,
if[*sender-for*](exec.snd.concepts#concept:sender-for "33.9.3Sender concepts[exec.snd.concepts]")<decltype((sndr)), when_all_with_variant_t> is false,
then the expression when_all_with_variant.transform_sender(sndr, env) is ill-formed;
otherwise, it is equivalent to:auto&& [_, _, ...child] = sndr;return when_all(into_variant(std::forward_like<decltype((sndr))>(child))...);
[*Note [1](#note-1)*:
This causes the when_all_with_variant(sndrs...) sender
to become when_all(into_variant(sndrs)...) when it is connected with a receiver
whose execution domain does not customize when_all_with_variant[.](#20.sentence-1)
— *end note*]