From f4fc084e93df69f0ecf3d3ec4d8a1613bb7f9cd0 Mon Sep 17 00:00:00 2001 From: Eisenwave Date: Sun, 5 Apr 2026 17:02:12 +0200 Subject: [PATCH] P3826R5 Fix Sender Algorithm Customization Fixes NB US 207-328, US 202-326, FR-031-219, FI-331, and CA-358 (C++26 CD). --- source/exec.tex | 512 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 365 insertions(+), 147 deletions(-) diff --git a/source/exec.tex b/source/exec.tex index 4455a1c991..7dfeac1e60 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -467,6 +467,8 @@ struct @\libglobal{get_forward_progress_guarantee_t}@ { @\unspec@ }; template struct @\libglobal{get_completion_scheduler_t}@ { @\unspec@ }; + template + struct @\libglobal{get_completion_domain_t}@ { @\unspec@ }; struct get_await_completion_adaptor_t { @\unspec@ }; inline constexpr get_domain_t @\libglobal{get_domain}@{}; @@ -476,6 +478,8 @@ inline constexpr get_forward_progress_guarantee_t @\libglobal{get_forward_progress_guarantee}@{}; template constexpr get_completion_scheduler_t @\libglobal{get_completion_scheduler}@{}; + template + constexpr get_completion_scheduler_t @\libglobal{get_completion_domain}@{}; inline constexpr get_await_completion_adaptor_t get_await_completion_adaptor{}; struct @\libglobal{get_env_t}@ { @\unspec@ }; @@ -484,6 +488,10 @@ template using @\libglobal{env_of_t}@ = decltype(get_env(declval())); + // \ref{exec.domain.indeterminate}, execution domains + template + struct indeterminate_domain; + // \ref{exec.domain.default}, execution domains struct default_domain; @@ -571,15 +579,9 @@ using tag_of_t = @\seebelow@; // \ref{exec.snd.transform}, sender transformations - template - requires (sizeof...(Env) <= 1) - constexpr @\libconcept{sender}@ decltype(auto) transform_sender( - Domain dom, Sndr&& sndr, const Env&... env) noexcept(@\seebelow@); - - // \ref{exec.snd.transform.env}, environment transformations - template - constexpr @\exposconcept{queryable}@ decltype(auto) transform_env( - Domain dom, Sndr&& sndr, Env&& env) noexcept; + template<@\libconcept{sender}@ Sndr, @\exposconcept{queryable}@ Env> + constexpr decltype(auto) transform_sender(Sndr&& sndr, + const Env& env) noexcept(@\seebelow@); // \ref{exec.snd.apply}, sender algorithm application template @@ -829,6 +831,26 @@ \rSec1[exec.queries]{Queries} +\rSec2[exec.queries.expos]{Query utilities} + +\pnum +\ref{exec.queries} makes use of the following exposition-only entities. + +\pnum +For subexpressions \tcode{q} and \tcode{tag} and pack \tcode{args}, +let \tcode{\exposid{TRY-QUERY}(q, tag, args...)} be expression-equivalent to +\tcode{\exposid{AS-CONST}(q).query(tag, args...)} +if that expression is well-formed, and +\tcode{\exposid{AS-CONST}(q).query(tag)} otherwise +except that \tcode{args...} is evaluated. + +\pnum +For subexpressions \tcode{q} and \tcode{tag} and pack \tcode{args}, +let \tcode{\exposid{HIDE-SCHED}(q)} be an object \tcode{o} such that +\tcode{o.query(\brk{}tag, args...)} is ill-formed when the decayed type of \tcode{tag} is +\tcode{get_scheduler_t} or \tcode{get_domain_t}, and +\tcode{q.query(tag, args...)} otherwise. + \rSec2[exec.fwd.env]{\tcode{forwarding_query}} \pnum @@ -937,7 +959,14 @@ The name \tcode{get_domain} denotes a query object. For a subexpression \tcode{env}, \tcode{get_domain(env)} is expression-equivalent to -\tcode{\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(env).query(get_domain))}. +\tcode{\exposid{MANDATE-NOTHROW}(D())}, +where \tcode{D} is the type of the first +of the following expressions that is well-formed: +\begin{itemize} +\item \tcode{auto(\exposid{AS-CONST}(env).query(get_domain))}. +\item \tcode{get_completion_domain(get_scheduler(env), \exposid{HIDE-SCHED}(env))}. +\item \tcode{default_domain()}, except that \tcode{env} is evaluated. +\end{itemize}. \pnum \tcode{forwarding_query(execution::get_domain)} is @@ -952,7 +981,9 @@ The name \tcode{get_scheduler} denotes a query object. For a subexpression \tcode{env}, \tcode{get_scheduler(env)} is expression-equivalent to -\tcode{\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(env).query(get_scheduler))}. +\tcode{get_completion_scheduler( +\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(env)\brk{}.query(get_scheduler)), +\exposid{HIDE-SCHED}(env))}. \mandates If the expression above is well-formed, @@ -1036,10 +1067,10 @@ Let \exposid{completion-fn} be a completion function\iref{exec.async.ops}; let \exposid{completion-fn-tag} be the associated completion tag of \exposid{completion-fn}; -let \tcode{args} be a pack of subexpressions; and +let \tcode{args} and \tcode{envs} be packs of subexpressions; and let \tcode{sndr} be a subexpression such that \tcode{\libconcept{sender}} is \tcode{true} and -\tcode{get_completion_scheduler<\exposid{completion-fn-tag}>(get_env(sndr))} +\tcode{get_completion_scheduler<\exposid{completion-fn-tag}>(get_env(sndr), envs...)} is well-formed and denotes a scheduler \tcode{sch}. \pnum @@ -1048,19 +1079,53 @@ from a sender's attributes. \pnum -For a subexpression \tcode{q}, -the expression \tcode{get_completion_scheduler<\exposid{completion-fn-tag}>(q)} +For subexpression \tcode{sch1} and pack \tcode{envs}, +let \tcode{sch2} be +\tcode{\exposid{TRY-QUERY}(sch1, get_completion_scheduler, envs...)} and +let \tcode{\exposid{RECURSE-QUERY}(sch1, envs...)} be +expression-equivalent to \tcode{sch1} +if \tcode{sch2} is ill-formed or +if \tcode{sch1} and \tcode{sch2} have the same type and compare equal; +otherwise, \tcode{\exposid{RECURSE-QUERY}(sch2, envs...)}. + +\pnum +For a subexpression \tcode{q} and pack \tcode{envs}, +the expression \tcode{get_completion_scheduler<\exposid{completion-fn-tag}>(q, envs...)} is ill-formed if \exposid{completion-fn-tag} is not one of \tcode{set_value_t}, \tcode{set_error_t}, or \tcode{set_stopped_t}. Otherwise, \tcode{get_completion_scheduler<\exposid{completion-fn-tag}>(q)} is expression-equivalent to +\begin{itemize} +\item \begin{codeblock} -@\exposid{MANDATE-NOTHROW}@(@\exposid{AS-CONST}@(q).query(get_completion_scheduler<@\exposid{completion-fn-tag}@>)) +@\exposid{MANDATE-NOTHROW}@(@\exposid{RECURSE-QUERY}@( + @\exposid{TRY-QUERY}@(q, get_completion_scheduler<@\exposid{completion-fn-tag}@>, envs...), envs...)) \end{codeblock} +if that expression is well-formed, +except that \tcode{envs...} is evaluated only once. +\item +Otherwise, \tcode{auto(q)} +if the type of \tcode{q} satisfies \libconcept{scheduler} and +\tcode{envs} is not an empty pack, +except that \tcode{envs...} is evaluated. +\item +Otherwise, \tcode{get_completion_scheduler<@\exposid{completion-fn-tag}@>(q, envs...)} +is ill-formed. +\end{itemize} \mandates -If the expression above is well-formed, +If \tcode{get_completion_scheduler<@\exposid{completion-fn-tag}@>(q, envs...)} +is well-formed, its type satisfies \libconcept{scheduler}. +\pnum +For a type \tcode{Tag}, subexpression \tcode{sndr}, and pack \tcode{envs}, +let \tcode{CS} be +\tcode{completion_signatures_of_t, decltype((envs))...>}. +If both \tcode{get_completion_scheduler(get_env(\newline sndr), envs...)} and +\tcode{CS} are well-formed and +\tcode{CS().\exposid{count-of}(Tag()) == 0} is \tcode{true}, +the program is ill-formed. + \pnum If an asynchronous operation created by connecting \tcode{sndr} with a receiver \tcode{rcvr} @@ -1074,6 +1139,80 @@ \tcode{forwarding_query(get_completion_scheduler<\exposid{completion-fn-tag}>)} is a core constant expression and has value \tcode{true}. +\rSec2[exec.get.compl.domain]{\tcode{execution::get_completion_domain}} + +\pnum +\tcode{get_completion_domain<\exposid{completion-tag}>} +obtains the completion domain associated with a completion tag +from a sender's attributes. + +\pnum +The name \tcode{get_completion_domain} denotes a query object template. +For a subexpression \tcode{attrs} and pack \tcode{envs}, +the expression \tcode{get_completion_domain<\exposid{completion-tag}>(attrs, envs...)} +is ill-formed if \exposid{completion-tag} is not one of +\tcode{void}, +\tcode{set_value_t}, +\tcode{set_error_t}, or +\tcode{set_stopped_t}. +Otherwise,\newline +\tcode{get_completion_domain<\exposid{completion-tag}>(attrs, envs...)} +is expression-equivalent to\newline +\tcode{\exposid{MANDATE-NOTHROW}(D())}, +where \tcode{D} is: +\begin{itemize} +\item +The type of +\tcode{\exposid{TRY-QUERY}(attrs, get_completion_domain<\exposid{completion-tag}>, envs...)} +if that expression is well-formed. +\item +Otherwise, the type of +\tcode{get_completion_domain(attrs, envs...)} +if \exposid{completion-tag} is void. +\item +Otherwise, the type of +\begin{codeblock} +@\exposid{TRY-QUERY}@(get_completion_scheduler(attrs, envs...), + get_completion_domain, envs...) +\end{codeblock} +if that expression is well-formed. +\item +Otherwise, \tcode{default_domain} if +\tcode{\libconcept{scheduler}} is \tcode{true} and +\tcode{envs} is not an empty pack. +\item +Otherwise, \tcode{get_completion_domain<\exposid{completion-tag}>(attrs, envs...)} +is ill-formed. +\end{itemize} + +\pnum +For a type \tcode{Tag}, subexpression \tcode{sndr}, and pack \tcode{envs}, +let \tcode{CS} be +\tcode{completion_signatures_of_t, decltype((envs))...>}. +If both \tcode{get_completion_domain(get_env(sndr), envs...)} and +\tcode{CS} are well-formed and +\tcode{CS().\exposid{count-of}(Tag()) == 0} is \tcode{true}, +the program is ill-formed. + +\pnum +Let \exposid{completion-fn} be a completion function\iref{exec.async.ops}; +let \exposid{completion-tag} be the associated completion tag of \exposid{completion-fn}; +let \tcode{args} and \tcode{envs} be packs of subexpressions; and +let \tcode{sndr} be a subexpression such that +\tcode{\libconcept{sender}} is \tcode{true} and +\tcode{get_completion_domain<\exposid{completion-tag}>(get_env(sndr), envs...)} +is well-formed and denotes a domain tag \tcode{D}. +If an asynchronous operation created by connecting +\tcode{sndr} with a receiver \tcode{rcvr} +causes the evaluation of \tcode{\exposid{completion-fn}(rcvr, args...)}, +the behavior is undefined +unless the evaluation happens on an execution agent of an execution resource +whose associated execution domain tag is \tcode{D}. + +The expression +\tcode{forwarding_query(get_completion_domain<\exposid{completion-tag}>)} +is a core constant expression and has value \tcode{true}. + \rSec2[exec.get.await.adapt]{\tcode{execution::get_await_completion_adaptor}} \pnum @@ -1111,9 +1250,6 @@ @\exposconcept{queryable}@ && requires(Sch&& sch) { { schedule(std::forward(sch)) } -> @\libconcept{sender}@; - { auto(get_completion_scheduler( - get_env(schedule(std::forward(sch))))) } - -> @\libconcept{same_as}@>; } && @\libconcept{equality_comparable}@> && @\libconcept{copyable}@>; @@ -1148,15 +1284,27 @@ \pnum For a given scheduler expression \tcode{sch}, -the expression +if the expression \tcode{get_completion_scheduler(get_env(schedule(sch)))} -shall compare equal to \tcode{sch}. +is well-formed, +it shall compare equal to \tcode{sch}. \pnum For a given scheduler expression \tcode{sch}, -if the expression \tcode{get_domain(sch)} is well-formed, -then the expression \tcode{get_domain(get_env(schedule(sch)))} -is also well-formed and has the same type. +type \tcode{T}, and +pack of subexpressions \tcode{envs}, +the following expressions are either both ill-formed, or +both well-formed with the same type: +\begin{itemize} +\item \tcode{get_completion_domain(sch, envs...)} +\item \tcode{get_completion_domain(get_env(schedule(sch)), envs...)} +\end{itemize} +Likewise, the following expressions are either both ill-formed, or +both well-formed with the same type and value: +\begin{itemize} +\item \tcode{get_completion_scheduler(sch, envs...)} +\item \tcode{get_completion_scheduler(get_env(schedule(sch)), envs...)} +\end{itemize} \pnum A scheduler type's destructor shall not block @@ -1336,6 +1484,8 @@ necessarily results in the potential evaluation\iref{basic.def.odr} of a set of completion operations whose first argument is a subexpression equal to \tcode{rcvr}. + +\pnum Let \tcode{Sigs} be a pack of completion signatures corresponding to this set of completion operations, and let \tcode{CS} be @@ -1347,6 +1497,56 @@ If none of the types in \tcode{Sigs} are dependent on the type \tcode{Env}, then the expression \tcode{get_completion_signatures()} is well-formed and its type is \tcode{CS}. + +\pnum +Each completion operation can potentially be evaluated +on one of several different execution agents +as determined by the semantics of the algorithm, +the environment of the receiver, and +the completions of any child senders. +For a completion tag \tcode{T}, +let \tcode{DsT} be a pack comprised of the set of domain tags +associated with the execution agents that could potentially evaluate +any of the operation's completions with tag \tcode{T}. +If there are no potentially evaluated completion operations +with tag type \tcode{T}, +then \tcode{get_completion_domain(get_env(sndr), env)} is ill-formed; +otherwise, it has type \tcode{\exposid{COMMON-DOMAIN}}\iref{exec.snd.expos}. +\begin{example} +Let \tcode{sndr2} be the sender \tcode{then(sndr, fn)}. +\tcode{sndr2} has the same \tcode{set_value} completion domain tag as \tcode{sndr}, +but if \tcode{fn}'s evaluation is potentially throwing, +\tcode{sndr}'s \tcode{set_error} completion domain tag would be +the \exposid{COMMON-DOMAIN} of \tcode{sndr}'s value and error completion domain tags, +in accordance with the semantics of the then algorithm\iref{exec.then}. +\end{example} + +\pnum +If \tcode{sndr} can determine that all of its completion operations +with tag \tcode{T} happen on execution agents +associated with a particular scheduler \tcode{sch} +(as determined by the semantics of the algorithm, +the environment of the receiver, and +the completion schedulers of any child senders), +then \tcode{get_completion_scheduler(get_env(sndr), env)} +is well-formed and has the type and value of \tcode{sch}; +otherwise, it is ill-formed. +\begin{example} +Let \tcode{sndr2} be the sender from the example above. +The \tcode{set_value} completion scheduler of \tcode{sndr2} is +the \tcode{set_value} completion scheduler of \tcode{sndr}, if any. +But \tcode{sndr2} can only report a \tcode{set_error} completion scheduler +when invocations of \tcode{fn} are not potentially throwing or +when \tcode{sndr} has no \tcode{set_error} completions. +When \tcode{fn} can throw, +\tcode{sndr2} could complete with \tcode{set_error} either +by forwarding an error completion from \tcode{sndr} or +by completing with the exception thrown by \tcode{fn}, +which would happen on an agent associated with \tcode{sndr}'s +\tcode{set_value} completion scheduler. +\end{example} + +\pnum If a user-provided implementation of the algorithm that produced \tcode{sndr} is selected instead of the default: @@ -1398,13 +1598,15 @@ \tcode{decltype(\exposid{FWD-ENV}(declval()))}. \pnum -For a query object \tcode{q} and a subexpression \tcode{v}, +For a query object \tcode{q}, +a subexpression \tcode{v}, and +a pack of subexpressions \tcode{args}, \tcode{\exposid{MAKE-ENV}(q, v)} is an expression \tcode{env} whose type satisfies \exposconcept{queryable} -such that the result of \tcode{env.query(q)} has +such that the result of \tcode{env.query(q, args...)} has a value equal to \tcode{v}\iref{concepts.equality}. Unless otherwise stated, -the object to which \tcode{env.query(q)} refers remains valid +the object to which \tcode{env.query(q, args...)} refers remains valid while \tcode{env} remains valid. \pnum @@ -1430,20 +1632,31 @@ with different types and value categories in different contexts for the same arguments. +\pnum +For a pack of subexpressions \tcode{domains}, +\tcode{\exposid{COMMON-DOMAIN}(domains...)} is expression-equivalent to +\tcode{common_type_t()} +if that expression is well-formed, and +\tcode{indeterminate_domain<\brk{}Ds...>()} otherwise, +where \tcode{Ds} is the pack of types consisting of +\tcode{decltype(auto(domains))...} with duplicate types removed. + +\pnum +For a type \tcode{Tag}, subexpression \tcode{sndr}, and pack \tcode{envs}, +\tcode{\exposid{COMPL-DOMAIN}(Tag, sndr, envs)} +is expression-equivalent to \tcode{D()}, +where \tcode{D} is +the type of \tcode{get_completion_domain(get_env(sndr), envs...)} +if that expression is well-formed or \tcode{envs} is an empty pack, and +\tcode{indeterminate_domain()} otherwise. + \pnum For a scheduler \tcode{sch}, -\tcode{\exposid{SCHED-ATTRS}(sch)} is an expression \tcode{o1} -whose type satisfies \exposconcept{queryable} -such that \tcode{o1.query(get_completion_scheduler)} is -an expression with the same type and value as \tcode{sch} -where \tcode{Tag} is one of \tcode{set_value_t} or \tcode{set_stopped_t}, and -such that \tcode{o1.query(get_domain)} is expression-equivalent to -\tcode{sch.query(get_domain)}. -\tcode{\exposid{SCHED-ENV}(sch)} is an expression \tcode{o2} +\tcode{\exposid{SCHED-ENV}(sch)} is an expression \tcode{o} whose type satisfies \exposconcept{queryable} -such that \tcode{o2.query(get_scheduler)} is a prvalue +such that \tcode{o.query(\brk{}get_scheduler)} is a prvalue with the same type and value as \tcode{sch}, and -such that \tcode{o2.query(get_domain)} is expression-equivalent to +such that \tcode{o.query(get_domain)} is expression-equivalent to \tcode{sch.query(get_domain)}. \pnum @@ -1467,31 +1680,6 @@ \end{codeblock} except that \tcode{rcvr} is evaluated only once. -\begin{itemdecl} -template - constexpr auto @\exposid{completion-domain}@(const Sndr& sndr) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\tcode{\exposid{COMPL-DOMAIN}(T)} is the type of the expression -\tcode{get_domain(get_completion_scheduler(get_env(sndr)))}. - -\pnum -\effects -If all of the types -\tcode{\exposid{COMPL-DOMAIN}(set_value_t)}, -\tcode{\exposid{COMPL-DOMAIN}(set_error_t)}, and\linebreak -\tcode{\exposid{COMPL-DOMAIN}(set_stopped_t)} are ill-formed, -\tcode{completion-domain(sndr)} is -a default-constructed prvalue of type \tcode{Default}. -Otherwise, if they all share a common type\iref{meta.trans.other} -(ignoring those types that are ill-formed), -then \tcode{\exposid{completion-domain}(sndr)} is -a default-constructed prvalue of that type. -Otherwise, \tcode{\exposid{completion-domain}(sndr)} is ill-formed. -\end{itemdescr} - \begin{itemdecl} template constexpr decltype(auto) @\exposid{query-with-default}@( @@ -1513,77 +1701,6 @@ The expression in the noexcept clause is \tcode{noexcept(e)}. \end{itemdescr} -\begin{itemdecl} -template - constexpr auto @\exposid{get-domain-early}@(const Sndr& sndr) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -return Domain(); -\end{codeblock} -where \tcode{Domain} is -the decayed type of the first of the following expressions that is well-formed: -\begin{itemize} -\item \tcode{get_domain(get_env(sndr))} -\item \tcode{\exposid{completion-domain}(sndr)} -\item \tcode{default_domain()} -\end{itemize} -\end{itemdescr} - -\begin{itemdecl} -template - constexpr auto @\exposid{get-domain-late}@(const Sndr& sndr, const Env& env) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{itemize} -\item -If \tcode{\exposconcept{sender-for}} is \tcode{true}, then -\begin{codeblock} -return Domain(); -\end{codeblock} -where \tcode{Domain} is the type of the following expression: -\begin{codeblock} -[] { - auto [_, sch, _] = sndr; - return @\exposid{query-with-default}@(get_domain, sch, default_domain()); -}(); -\end{codeblock} -\begin{note} -The \tcode{continues_on} algorithm works -in tandem with \tcode{schedule_from}\iref{exec.schedule.from} -to give scheduler authors a way to customize both -how to transition onto (\tcode{continues_on}) and off of (\tcode{schedule_from}) -a given execution context. -Thus, \tcode{continues_on} ignores the domain of the predecessor and -uses the domain of the destination scheduler to select a customization, -a property that is unique to \tcode{continues_on}. -That is why it is given special treatment here. -\end{note} -\item -Otherwise, -\begin{codeblock} -return Domain(); -\end{codeblock} -where \tcode{Domain} is the first of the following expressions -that is well-formed and whose type is not \tcode{void}: -\begin{itemize} -\item \tcode{get_domain(get_env(sndr))} -\item \tcode{\exposid{completion-domain}(sndr)} -\item \tcode{get_domain(env)} -\item \tcode{get_domain(get_scheduler(env))} -\item \tcode{default_domain()} -\end{itemize} -\end{itemize} -\end{itemdescr} - \pnum \begin{codeblock} template<@\exposconcept{callable}@ Fun> @@ -1894,7 +2011,6 @@ \begin{codeblock} namespace std::execution { struct @\exposidnc{default-impls}@ { // \expos - static constexpr auto @\exposidnc{get-attrs}@ = @\seebelownc@; // \expos static constexpr auto @\exposidnc{get-env}@ = @\seebelownc@; // \expos static constexpr auto @\exposidnc{get-state}@ = @\seebelownc@; // \expos static constexpr auto @\exposidnc{start}@ = @\seebelownc@; // \expos @@ -1909,18 +2025,6 @@ } \end{codeblock} -\pnum -The member \tcode{\exposid{default-impls}::\exposid{get-attrs}} -is initialized with a callable object equivalent to the following lambda: -\begin{codeblock} -[](const auto&, const auto&... child) noexcept -> decltype(auto) { - if constexpr (sizeof...(child) == 1) - return (@\exposid{FWD-ENV}@(get_env(child)), ...); - else - return env<>(); -} -\end{codeblock} - \pnum The member \tcode{\exposid{default-impls}::\exposid{get-env}} is initialized with a callable object equivalent to the following lambda: @@ -2105,6 +2209,19 @@ }; \end{codeblock} +\pnum +\indexlibraryglobal{\exposid{not-a-scheduler}}% +\indexlibrarymember{schedule}{\exposid{not-a-sender}}% +\begin{codeblock} +struct @\exposid{not-a-scheduler}@ { + using scheduler_concept = scheduler_t; + + constexpr auto schedule() const noexcept { + return @\exposid{not-a-sender}@(); + } +}; +\end{codeblock} + \pnum \indexlibraryglobal{\exposid{decay-copyable-result-datums}} %%FIXME: Should this be in a namespace? @@ -2150,6 +2267,48 @@ \end{itemize} \end{itemdescr} +\indexlibraryglobal{\exposid{call-with-default}} +\begin{itemdecl} +template + constexpr decltype(auto) @\exposid{call-with-default}@( + Fn&& fn, Default&& value, Args&&... args) noexcept(@\seebelow@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{expr} be the expression +\tcode{std::forward(fn)(std::forward(args)...)} +if that expression is well-formed; +otherwise, it is \tcode{static_cast(std::forward(value))}. + +\pnum +\returns +\tcode{exprs}. + +\pnum +\remarks +The expression in the \tcode{noexcept} clause is \tcode{noexcept(expr)}. +\end{itemdescr} + +\pnum +\indexlibraryglobal{\exposid{inline-attrs}}% +\begin{codeblock} +template +struct @\exposid{inline-attrs}@ { + @\seebelow@ +}; +\end{codeblock} + +\pnum +For a subexpression \tcode{env}, +\tcode{\exposid{inline-attrs}{}.query(get_completion_scheduler, env)} +is expres\-sion-equivalent to \tcode{get_scheduler(env)}. + +\pnum +For a subexpression \tcode{env}, +\tcode{\exposid{inline-attrs}{}.query(get_completion_domain, env)} +is expression-equivalent to \tcode{get_domain(env)}. + \rSec2[exec.snd.concepts]{Sender concepts} \pnum @@ -2448,6 +2607,65 @@ its members need not be defined. \end{note} +\rSec2[exec.domain.indeterminate]{\tcode{execution::indeterminate_domain}} + +\pnum +\indexlibraryglobal{indeterminate_domain}% +\indexlibraryctor{indeterminate_domain}% +\begin{codeblock} +namespace std::execution { + template + struct indeterminate_domain { + indeterminate_domain() = default; + constexpr indeterminate_domain(auto&&) noexcept {} + + template + static constexpr decltype(auto) transform_sender(Tag, Sndr&& sndr, const Env& env) + noexcept(@\seebelow@); + }; +} +\end{codeblock} + +\indexlibrarymember{transform_sender}{indeterminate_domain}% +\begin{itemdecl} +template + static constexpr decltype(auto) transform_sender(Tag, Sndr&& sndr, const Env& env) + noexcept(@\seebelow@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +For each type \tcode{D} in \tcode{Domains...}, +the expression +\begin{codeblock} +D().transform_sender(Tag(), std::forward(sndr), env) +\end{codeblock} +is either ill-formed or has the same decayed type as +\tcode{default_domain().transform_sender(Tag(), std::forward(sndr), env)}. + +\pnum +\returns +\tcode{default_domain().transform_sender(Tag(), std::forward(sndr), env)}. + +\pnum +\remarks +For a pack of types \tcode{Ds}, +\begin{codeblock} +common_type_t, indeterminate_domain> +\end{codeblock} +is \tcode{indeterminate_domain}, +where \tcode{Us} is a pack that contains each type in +\tcode{Domains..., Ds...} except with duplicate types removed. +For a type \tcode{D} that is not a specialization of \tcode{indeterminate_domain}, +\tcode{common_type_t, D>} +is \tcode{D} if \tcode{Domains} is an empty pack, and +\begin{codeblock} +\tcode{common_type_t, indeterminate_domain>} +\end{codeblock} +otherwise. +\end{itemdescr} + \rSec2[exec.domain.default]{\tcode{execution::default_domain}} \pnum