|
3900 | 3900 | \tcode{set_value}, \tcode{set_error}, and \tcode{set_stopped}, respectively. |
3901 | 3901 | Let the expression \exposid{let-cpo} be one of |
3902 | 3902 | \tcode{let_value}, \tcode{let_error}, or \tcode{let_stopped}. |
| 3903 | +Let \exposid{let-tag} denote a unique, empty class type for each of |
| 3904 | +\tcode{let_value}, \tcode{let_error}, and \tcode{let_stopped}. |
3903 | 3905 | For a subexpression \tcode{sndr}, |
3904 | 3906 | let \tcode{\exposid{let-env}(sndr)} be expression-equivalent to |
3905 | 3907 | the first well-formed expression below: |
|
3931 | 3933 | \end{codeblock} |
3932 | 3934 | except that \tcode{sndr} is evaluated only once. |
3933 | 3935 |
|
| 3936 | +\pnum |
| 3937 | +Let \exposid{let-data} denote the following exposition-only class template: |
| 3938 | +\begin{codeblock} |
| 3939 | +template<class Sndr, class Fn> |
| 3940 | +struct @\exposid{let-data}@ { |
| 3941 | + Sndr @\exposid{sndr}@; // \expos |
| 3942 | + Fn @\exposid{fn}@; // \expos |
| 3943 | +}; |
| 3944 | +\end{codeblock} |
| 3945 | + |
| 3946 | +\pnum |
| 3947 | +Then let the expression \tcode{\exposid{let-cpo}.transform_sender(s, es...)} |
| 3948 | +be expression-equivalent to: |
| 3949 | +\begin{codeblock} |
| 3950 | +@\exposid{make-sender}@(@\exposid{let-tag}@{}, @\exposid{let-data}@{s.template @\exposid{get}@<2>(), s.template @\exposid{get}@<1>()}) |
| 3951 | +\end{codeblock} |
| 3952 | +except that \tcode{s} is evaluated only once. |
| 3953 | + |
3934 | 3954 | \pnum |
3935 | 3955 | The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos} |
3936 | | -is specialized for \exposid{let-cpo} as follows: |
| 3956 | +is specialized for \exposid{let-tag} as follows: |
3937 | 3957 | \indexlibraryglobal{\exposid{impls-for}<\exposid{decayed-typeof}<\exposid{let-cpo}>>} |
3938 | 3958 | \begin{codeblock} |
3939 | 3959 | namespace std::execution { |
3940 | | - template<class State, class Rcvr, class... Args> |
3941 | | - void @\exposid{let-bind}@(State& state, Rcvr& rcvr, Args&&... args); // \expos |
3942 | | - |
3943 | 3960 | template<> |
3944 | | - struct @\exposid{impls-for}@<@\exposid{decayed-typeof}@<@\exposid{let-cpo}@>> : @\exposid{default-impls}@ { |
| 3961 | + struct @\exposid{impls-for}@<@\exposid{let-tag}@> : @\exposid{default-impls}@ { |
3945 | 3962 | static constexpr auto @\exposid{get-state}@ = @\seebelow@; |
3946 | | - static constexpr auto @\exposid{complete}@ = @\seebelow@; |
| 3963 | + static constexpr auto @\exposid{start}@ = @\seebelow@; |
3947 | 3964 |
|
3948 | 3965 | template<class Sndr, class... Env> |
3949 | 3966 | static consteval void @\exposid{check-types}@(); |
|
4032 | 4049 | \end{itemdescr} |
4033 | 4050 |
|
4034 | 4051 | \pnum |
4035 | | -\tcode{\exposid{impls-for}<\exposid{decayed-typeof}<\exposid{let-cpo}>>::\exposid{get-state}} |
| 4052 | +Let \exposid{let-state} denote the following exposition-only class template: |
| 4053 | +\begin{codeblock} |
| 4054 | +template<class Cpo, class Sndr, class Fn, class Rcvr, class ArgsVariant, class OpsVariant> |
| 4055 | +struct @\exposid{let-state}@ { |
| 4056 | + using @\exposid{env_t}@ = decltype(@\exposid{let-env}@(declval<Sndr>())); // \expos |
| 4057 | + Fn @\exposid{fn}@; // \expos |
| 4058 | + env_t @\exposid{env}@; // \expos |
| 4059 | + ArgsVariant @\exposid{args}@; // \expos |
| 4060 | + OpsVariant @\exposid{ops}@; // \expos |
| 4061 | + |
| 4062 | + template<class Tag, class... Ts> |
| 4063 | + constexpr void @\exposid{impl}@(Rcvr& rcvr, Tag tag, Ts&&... ts) noexcept // \expos |
| 4064 | + { |
| 4065 | + using args_t = @\exposid{decayed-tuple}@<Ts...>; |
| 4066 | + using receiver_type = @\exposid{receiver2}@<Rcvr, env_t>; |
| 4067 | + using sender_type = apply_result_t<Fn, args_t&>; |
| 4068 | + if constexpr (is_same_v<Tag, Cpo>) { |
| 4069 | + try { |
| 4070 | + auto& tuple = @\exposid{args}@.template emplace<args_t>(std::forward<Ts>(ts)...); |
| 4071 | + @\exposid{ops}@.template emplace<monostate>(); |
| 4072 | + auto&& sndr = apply(std::move(@\exposid{fn}@), tuple); |
| 4073 | + using op_t = connect_result_t<sender_type, receiver_type>; |
| 4074 | + auto mkop2 = [&] { |
| 4075 | + return connect(std::forward<sender_type>(sndr), |
| 4076 | + receiver_type{@\exposid{rcvr}@, @\exposid{env}@}); |
| 4077 | + }; |
| 4078 | + auto& op = @\exposid{ops}@.template emplace<op_t>(@\exposid{emplace-from}@{mkop2}); |
| 4079 | + start(op); |
| 4080 | + } catch (...) { |
| 4081 | + constexpr bool nothrow = |
| 4082 | + is_nothrow_constructible_v<args_t, Ts...> && |
| 4083 | + is_nothrow_applicable_v<Fn, args_t&> && |
| 4084 | + noexcept(connect(declval<sender_type>(), receiver_type{@\exposid{rcvr}@, @\exposid{env}@})); |
| 4085 | + if constexpr (!nothrow) { |
| 4086 | + set_error(std::move(@\exposid{rcvr}@), current_exception()); |
| 4087 | + } |
| 4088 | + } |
| 4089 | + } else { |
| 4090 | + tag(std::move(@\exposid{rcvr}@), std::forward<Ts>(ts)...); |
| 4091 | + } |
| 4092 | + } |
| 4093 | + |
| 4094 | + struct @\exposid{receiver}@ { // \expos |
| 4095 | + @\exposid{let-state}@& state; // \expos |
| 4096 | + Rcvr& @\exposid{rcvr}@; // \expos |
| 4097 | + |
| 4098 | + using receiver_concept = receiver_t; |
| 4099 | + |
| 4100 | + template<class... Args> |
| 4101 | + constexpr void set_value(Args&&... args) noexcept { |
| 4102 | + @\exposid{state}@.@\exposid{impl}@(@\exposid{rcvr}@, execution::set_value, std::forward<Args>(args)...); |
| 4103 | + } |
| 4104 | + template<class... Args> |
| 4105 | + constexpr void set_error(Args&&... args) noexcept { |
| 4106 | + @\exposid{state}@.@\exposid{impl}@(@\exposid{rcvr}@, execution::set_error, std::forward<Args>(args)...); |
| 4107 | + } |
| 4108 | + template<class... Args> |
| 4109 | + constexpr void set_stopped(Args&&... args) noexcept { |
| 4110 | + @\exposid{state}@.@\exposid{impl}@(@\exposid{rcvr}@, execution::set_stopped, std::forward<Args>(args)...); |
| 4111 | + } |
| 4112 | + |
| 4113 | + constexpr env_of_t<const Rcvr&> get_env() const noexcept { |
| 4114 | + return execution::get_env(@\exposid{rcvr}@); |
| 4115 | + } |
| 4116 | + |
| 4117 | + }; |
| 4118 | + |
| 4119 | + using @\exposid{op_t}@ = connect_result_t<Sndr, @\exposid{receiver}@>; // \expos |
| 4120 | + |
| 4121 | + constexpr @\exposid{let-state}@(Sndr&& sndr, Fn fn, Rcvr& rcvr) // \expos |
| 4122 | + : fn(std::move(fn)), env(@\exposid{let-env}@(sndr)), |
| 4123 | + ops(in_place_type<@\exposid{op_t}@>, std::forward<Sndr>(sndr), |
| 4124 | + @\exposid{receiver}@{*this, rcvr}) |
| 4125 | + {} |
| 4126 | + |
| 4127 | +}; |
| 4128 | +\end{codeblock} |
| 4129 | + |
| 4130 | +\pnum |
| 4131 | +\tcode{\exposid{impls-for}<\exposid{let-tag}>::\exposid{get-state}} |
4036 | 4132 | is initialized with a callable object equivalent to the following: |
4037 | 4133 | \begin{codeblock} |
4038 | 4134 | []<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) requires @\seebelow@ { |
4039 | | - auto& [_, fn, child] = sndr; |
| 4135 | + auto& [_, data] = sndr; |
| 4136 | + auto& [child, fn] = data; |
| 4137 | + using child_t = decltype(std::forward_like<Sndr>(child)); |
4040 | 4138 | using fn_t = decay_t<decltype(fn)>; |
4041 | | - using env_t = decltype(@\exposid{let-env}@(child)); |
4042 | 4139 | using args_variant_t = @\seebelow@; |
4043 | | - using ops2_variant_t = @\seebelow@; |
4044 | | - |
4045 | | - struct @\exposid{state-type}@ { |
4046 | | - fn_t @\exposid{fn}@; // \expos |
4047 | | - env_t @\exposid{env}@; // \expos |
4048 | | - args_variant_t @\exposid{args}@; // \expos |
4049 | | - ops2_variant_t @\exposid{ops2}@; // \expos |
4050 | | - }; |
4051 | | - return @\exposid{state-type}@{@\exposid{allocator-aware-forward}@(std::forward_like<Sndr>(fn), rcvr), |
4052 | | - @\exposid{let-env}@(child), {}, {}}; |
| 4140 | + using ops_variant_t = @\seebelow@; |
| 4141 | + using state_t = @\exposid{let-state}@<@\exposid{decayed-typeof}@<@\exposid{set-cpo}@>, child_t, fn_t, Rcvr, |
| 4142 | + args_variant_t, ops_variant_t>; |
| 4143 | + return state_t(std::forward_like<Sndr>(child), std::forward_like<Sndr>(fn), @\exposid{rcvr}@); |
4053 | 4144 | } |
4054 | 4145 | \end{codeblock} |
4055 | 4146 |
|
|
4071 | 4162 | let \exposid{as-sndr2} be an alias template |
4072 | 4163 | such that \tcode{\exposid{as-sndr2}<Tag(Args...)>} denotes |
4073 | 4164 | the type \tcode{\exposid{call-result-t}<F, decay_t<Args>\&...>}. |
4074 | | -Then \tcode{ops2_variant_t} denotes |
| 4165 | +Then \tcode{ops_variant_t} denotes |
4075 | 4166 | the type |
4076 | 4167 | \begin{codeblock} |
4077 | | -variant<monostate, connect_result_t<@\exposid{as-sndr2}@<LetSigs>, @\exposid{receiver2}@<Rcvr, env_t>>...> |
| 4168 | +variant<monostate, |
| 4169 | + connect_result_t<child_t, @\exposid{let-state}@::@\exposid{receiver}@>, |
| 4170 | + connect_result_t<@\exposid{as-sndr2}@<LetSigs>, @\exposid{receiver2}@<Rcvr, env_t>>...> |
4078 | 4171 | \end{codeblock} |
4079 | 4172 | except with duplicate types removed. |
4080 | 4173 |
|
|
4084 | 4177 | the types \tcode{args_variant_t} and \tcode{ops2_variant_t} are well-formed. |
4085 | 4178 |
|
4086 | 4179 | \pnum |
4087 | | -The exposition-only function template \exposid{let-bind} |
4088 | | -has effects equivalent to: |
4089 | | -\begin{codeblock} |
4090 | | -using args_t = @\exposid{decayed-tuple}@<Args...>; |
4091 | | -auto mkop2 = [&] { |
4092 | | - return connect( |
4093 | | - apply(std::move(state.fn), |
4094 | | - state.args.template emplace<args_t>(std::forward<Args>(args)...)), |
4095 | | - @\exposid{receiver2}@{rcvr, std::move(state.env)}); |
4096 | | -}; |
4097 | | -start(state.ops2.template emplace<decltype(mkop2())>(@\exposid{emplace-from}@{mkop2})); |
4098 | | -\end{codeblock} |
4099 | | - |
4100 | | -\pnum |
4101 | | -\tcode{\exposid{impls-for}<\exposid{decayed-typeof}<\exposid{let-cpo}>>::\exposid{complete}} |
| 4180 | +\tcode{\exposid{impls-for}<\exposid{let-tag}>::\exposid{start}} |
4102 | 4181 | is initialized with a callable object equivalent to the following: |
4103 | 4182 | \begin{codeblock} |
4104 | | -[]<class Tag, class... Args> |
4105 | | - (auto, auto& state, auto& rcvr, Tag, Args&&... args) noexcept -> void { |
4106 | | - if constexpr (@\libconcept{same_as}@<Tag, @\exposid{decayed-typeof}@<@\exposid{set-cpo}@>>) { |
4107 | | - @\exposid{TRY-EVAL}@(rcvr, @\exposid{let-bind}@(state, rcvr, std::forward<Args>(args)...)); |
4108 | | - } else { |
4109 | | - Tag()(std::move(rcvr), std::forward<Args>(args)...); |
4110 | | - } |
4111 | | - } |
| 4183 | +[]<class State, class Rcvr>(State& state, Rcvr&) noexcept { |
| 4184 | + start(get<typename State::@\exposid{op_t}@>(state.@\exposid{ops}@)); |
| 4185 | +} |
4112 | 4186 | \end{codeblock} |
4113 | 4187 |
|
4114 | 4188 | \pnum |
|
0 commit comments