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

168 lines
8.9 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.associate]
# 33 Execution control library [[exec]](./#exec)
## 33.9 Senders [[exec.snd]](exec.snd#exec.associate)
### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#exec.associate)
#### 33.9.12.16 execution::associate [exec.associate]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4897)
associate tries to associate
a sender with an async scope such that
the scope can track the lifetime of any asynchronous operations
created with the sender[.](#1.sentence-1)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4903)
Let *associate-data* be the following exposition-only class template:
[🔗](#lib:execution::associate-data)
namespace std::execution {template<[scope_token](exec.scope.concepts#concept:scope_token "33.14.1Execution scope concepts[exec.scope.concepts]") Token, [sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]") Sender>struct *associate-data* { // *exposition only*using *wrap-sender* = // *exposition only* remove_cvref_t<decltype(declval<Token&>().wrap(declval<Sender>()))>; explicit *associate-data*(Token t, Sender&& s): *sndr*(t.wrap(std::forward<Sender>(s))), *token*(t) {if (!*token*.try_associate())*sndr*.reset(); }*associate-data*(const *associate-data*& other)noexcept(is_nothrow_copy_constructible_v<*wrap-sender*> &&noexcept(other.*token*.try_associate())); *associate-data*(*associate-data*&& other)noexcept(is_nothrow_move_constructible_v<*wrap-sender*>); ~*associate-data*();
optional<pair<Token, *wrap-sender*>> release() && noexcept(is_nothrow_move_constructible_v<*wrap-sender*>); private: optional<*wrap-sender*> *sndr*; // *exposition only* Token *token*; // *exposition only*}; template<[scope_token](exec.scope.concepts#concept:scope_token "33.14.1Execution scope concepts[exec.scope.concepts]") Token, [sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]") Sender>*associate-data*(Token, Sender&&) -> *associate-data*<Token, Sender>;}
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4943)
For an *associate-data* object a,a.*sndr*.has_value() is true if and only if
an association was successfully made and is owned by a[.](#3.sentence-1)
[🔗](#lib:execution::associate-data,constructor)
`associate-data(const associate-data& other)
noexcept(is_nothrow_copy_constructible_v<wrap-sender> &&
noexcept(other.token.try_associate()));
`
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4957)
*Constraints*: [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<*wrap-sender*> is true[.](#4.sentence-1)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4961)
*Effects*: Value-initializes *sndr* and
initializes *token* with other.*token*[.](#5.sentence-1)
If other.*sndr*.has_value() is false,
no further effects;
otherwise,
calls *token*.try_associate() and,
if that returns true,
calls *sndr*.emplace(*other.*sndr*) and,
if that exits with an exception,
calls *token*.disassociate() before propagating the exception[.](#5.sentence-2)
[🔗](#lib:execution::associate-data,constructor_)
`associate-data(associate-data&& other)
noexcept(is_nothrow_move_constructible_v<wrap-sender>);
`
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4982)
*Effects*: Initializes *sndr* with std::move(other.*sndr*) and
initializes *token* with std::move(other.*token*) and
then calls other.*sndr*.reset()[.](#6.sentence-1)
[🔗](#lib:execution::associate-data,destructor)
`~associate-data();
`
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4995)
*Effects*: If *sndr*.has_value() returns false then no effect;
otherwise, invokes *sndr*.reset() before invoking *token*.disassociate()[.](#7.sentence-1)
[🔗](#lib:release,execution::associate-data)
`optional<pair<Token, wrap-sender>>
release() && noexcept(is_nothrow_move_constructible_v<wrap-sender>);
`
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5009)
*Effects*: If *sndr*.has_value() returns false then
returns an optional that does not contain a value;
otherwise returns an optional containing a value of type pair<Token, *wrap-sender*> as if by:return optional(pair(*token*, std::move(**sndr*)));
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5020)
*Postconditions*: *sndr* does not contain a value[.](#9.sentence-1)
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5025)
The name associate denotes a pipeable sender adaptor object[.](#10.sentence-1)
For subexpressions sndr and token:
- [(10.1)](#10.1)
If decltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]"), orremove_cvref_t<decltype((token))> does not satisfy [scope_token](exec.scope.concepts#concept:scope_token "33.14.1Execution scope concepts[exec.scope.concepts]"), thenassociate(sndr, token) is ill-formed.
- [(10.2)](#10.2)
Otherwise,
the expression associate(sndr, token) is expression-equivalent to:transform_sender(*get-domain-early*(sndr), *make-sender*(associate, *associate-data*(token, sndr))) except that sndr is evaluated only once.
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5045)
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2Exposition-only entities"))
is specialized for associate_t as follows:
[🔗](#lib:execution::impls-for%3cassociate_t%3e)
namespace std::execution {template<>struct *impls-for*<associate_t> : *default-impls* {static constexpr auto *get-state* = *see below*; // *exposition only*static constexpr auto *start* = *see below*; // *exposition only*template<class Sndr, class... Env>static consteval void *check-types*() { // *exposition only*using associate_data_t = remove_cvref_t<*data-type*<Sndr>>; using child_type_t = typename associate_data_t::*wrap-sender*; (void)get_completion_signatures<child_type_t, *FWD-ENV-T*(Env)...>(); }};}
[12](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5066)
The member *impls-for*<associate_t>::*get-state* is initialized with a callable object equivalent to the following lambda:
[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) noexcept(*see below*) {auto [_, data] = std::forward<Sndr>(sndr); auto dataParts = std::move(data).release(); using scope_tkn = decltype(dataParts->first); using wrap_sender = decltype(dataParts->second); using op_t = connect_result_t<wrap_sender, Rcvr>; struct op_state {bool *associated* = false; // *exposition only*union { Rcvr* *rcvr*; // *exposition only*struct { scope_tkn *token*; // *exposition only* op_t *op*; // *exposition only*} *assoc*; // *exposition only*}; explicit op_state(Rcvr& r) noexcept: *rcvr*(addressof(r)) {}explicit op_state(scope_tkn tkn, wrap_sender&& sndr, Rcvr& r) try: *associated*(true), *assoc*(tkn, connect(std::move(sndr), std::move(r))) {}catch (...) { tkn.disassociate(); throw; } op_state(op_state&&) = delete; ~op_state() {if (*associated*) {*assoc*.*op*.~op_t(); *assoc*.*token*.disassociate(); *assoc*.*token*.~scope_tkn(); }}void *run*() noexcept { // *exposition only*if (*associated*) start(*assoc*.*op*); else set_stopped(std::move(**rcvr*)); }}; if (dataParts)return op_state{std::move(dataParts->first), std::move(dataParts->second), rcvr}; elsereturn op_state{rcvr};}
[13](#13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5126)
The expression in the noexcept clause of*impls-for*<associate_t>::*get-state* isis_nothrow_constructible_v<remove_cvref_t<Sndr>, Sndr> && is_nothrow_move_constructible_v<*wrap-sender*> &&[*nothrow-callable*](functional.syn#concept:nothrow-callable "22.10.2Header <functional> synopsis[functional.syn]")<connect_t, *wrap-sender*, Rcvr> where *wrap-sender* is the typeremove_cvref_t<*data-type*<Sndr>>::*wrap-sender*[.](#13.sentence-1)
[14](#14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5137)
The member *impls-for*<associate_t>::*start* is initialized with a callable object equivalent to the following lambda:[](auto& state, auto&) noexcept -> void { state.*run*();}
[15](#15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5146)
The evaluation of associate(sndr, token) may cause side effects observable
via token's associated async scope object[.](#15.sentence-1)