Skip to content

Commit db01d39

Browse files
committed
remove receiver_adaptor
1 parent 87adc76 commit db01d39

File tree

1 file changed

+61
-183
lines changed

1 file changed

+61
-183
lines changed

execution.bs

Lines changed: 61 additions & 183 deletions
Original file line numberDiff line numberDiff line change
@@ -648,18 +648,16 @@ implementations.
648648
```c++
649649
namespace stdexec = std::execution;
650650

651-
template<class R, class F>
652-
class _then_receiver
653-
: public stdexec::receiver_adaptor<_then_receiver<R, F>, R> {
651+
template <class R, class F>
652+
class _then_receiver : public R {
654653
F f_;
655654

656655
public:
657-
_then_receiver(R r, F f)
658-
: stdexec::receiver_adaptor<_then_receiver, R>{std::move(r)}
659-
, f_(std::move(f)) {}
656+
_then_receiver(R r, F f) : R(std::move(r)), f_(std::move(f)) {}
660657

661-
// Customize set_value by invoking the callable and passing the result to the inner receiver
662-
template<class... As>
658+
// Customize set_value by invoking the callable and passing the result to
659+
// the inner receiver
660+
template <class... As>
663661
requires std::invocable<F, As...>
664662
void set_value(As&&... as) && noexcept {
665663
try {
@@ -670,7 +668,7 @@ class _then_receiver
670668
}
671669
};
672670

673-
template<stdexec::sender S, class F>
671+
template <stdexec::sender S, class F>
674672
struct _then_sender {
675673
using sender_concept = stdexec::sender_t;
676674
S s_;
@@ -680,28 +678,30 @@ struct _then_sender {
680678
using _set_value_t = stdexec::completion_signatures<
681679
stdexec::set_value_t(std::invoke_result_t<F, Args...>)>;
682680

681+
using _except_ptr_sig =
682+
stdexec::completion_signatures<stdexec::set_error_t(std::exception_ptr)>;
683+
683684
// Compute the completion signatures
684-
template<class Env>
685+
template <class Env>
685686
auto get_completion_signatures(Env&& env) && noexcept
686-
-> stdexec::transform_completion_signatures_of<S, Env,
687-
stdexec::completion_signatures<stdexec::set_error_t(std::exception_ptr)>,
688-
_set_value_t> {
687+
-> stdexec::transform_completion_signatures_of<
688+
S, Env, _except_ptr_sig, _set_value_t> {
689689
return {};
690690
}
691691

692692
// Connect:
693-
template<stdexec::receiver R>
693+
template <stdexec::receiver R>
694694
auto connect(R r) && -> stdexec::connect_result_t<S, _then_receiver<R, F>> {
695-
return stdexec::connect(
696-
(S&&) s_, _then_receiver<R, F>{(R&&) r, (F&&) f_});
695+
return stdexec::connect(
696+
(S&&) s_, _then_receiver{(R&&) r, (F&&) f_});
697697
}
698698

699699
decltype(auto) get_env() const noexcept {
700700
return get_env(s_);
701701
}
702702
};
703703

704-
template<stdexec::sender S, class F>
704+
template <stdexec::sender S, class F>
705705
stdexec::sender auto then(S s, F f) {
706706
return _then_sender<S, F>{(S&&) s, (F&&) f};
707707
}
@@ -714,15 +714,11 @@ well as all receiver queries, are passed through unchanged.
714714

715715
In detail, it does the following:
716716

717-
1. Defines a receiver in terms of `execution::receiver_adaptor` that aggregates
718-
another receiver and an invocable that:
717+
1. Defines a receiver in terms of receiver and an invocable that:
719718
* Defines a constrained `set_value` member function for transforming the
720719
value channel.
721720
* Delegates `set_error` and `set_stopped` to the inner receiver.
722721

723-
The `set_error` and `set_stopped` member functions are provided by
724-
`receiver_adaptor`.
725-
726722
2. Defines a sender that aggregates another sender and the invocable, which
727723
defines a `connect` member function that wraps the incoming receiver in the
728724
receiver from (1) and passes it and the incoming sender to
@@ -742,10 +738,12 @@ concept _decays_to = same_as<decay_t<From>, To>;
742738
// _conv needed so we can emplace construct non-movable types into
743739
// a std::optional.
744740
template<invocable F>
745-
requires is_nothrow_move_constructible_v<F>
746741
struct _conv {
747742
F f_;
743+
744+
static_assert(is_nothrow_move_constructible_v<F>);
748745
explicit _conv(F f) noexcept : f_((F&&) f) {}
746+
749747
operator invoke_result_t<F>() && {
750748
return ((F&&) f_)();
751749
}
@@ -754,20 +752,27 @@ struct _conv {
754752
template<class S, class R>
755753
struct _retry_op;
756754

757-
// pass through all customizations except set_error, which retries the operation.
755+
// pass through all customizations except set_error, which retries
756+
// the operation.
758757
template<class S, class R>
759-
struct _retry_receiver
760-
: stdexec::receiver_adaptor<_retry_receiver<S, R>> {
758+
struct _retry_receiver {
761759
_retry_op<S, R>* o_;
762760

763-
R&& base() && noexcept { return std::move(o_->r_); }
764-
const R& base() const & noexcept { return o_->r_; }
765-
766-
explicit _retry_receiver(_retry_op<S, R>* o) : o_(o) {}
761+
void set_value(auto&&... as) && noexcept {
762+
stdexec::set_value(std::move(o_->r_), (decltype(as)&&) as...);
763+
}
767764

768765
void set_error(auto&&) && noexcept {
769766
o_->_retry(); // This causes the op to be retried
770767
}
768+
769+
void set_stopped() && noexcept {
770+
stdexec::set_stopped(std::move(o_->r_));
771+
}
772+
773+
decltype(auto) get_env() const noexcept {
774+
return get_env(o_->r_);
775+
}
771776
};
772777

773778
// Hold the nested operation state in an optional so we can
@@ -1213,8 +1218,6 @@ that the completion-signal of will be transferred to the given context.
12131218
10. Some additional utilities are added:
12141219
* <b>`run_loop`</b>: An execution resource that provides a multi-producer,
12151220
single-consumer, first-in-first-out work queue.
1216-
* <b>`receiver_adaptor`</b>: A utility for algorithm authors for defining one
1217-
receiver type in terms of another.
12181221
* <b>`completion_signatures`</b> and <b>`transform_completion_signatures`</b>:
12191222
Utilities for describing the ways in which a sender can complete in a
12201223
declarative syntax.
@@ -1461,8 +1464,11 @@ The changes since R8 are as follows:
14611464
* The `tag_invoke` mechanism has been replace with member functions
14621465
for customizations as per \[P2855](https://wg21.link/p2855).
14631466

1464-
* The removal of `tag_invoke` necessitated a respecification of the
1465-
`receiver_adaptor` utility.
1467+
* Per guidance from LWG and LEWG, `receiver_adaptor` has been removed.
1468+
1469+
* The `receiver` concept is tweaked to requires that receiver types are not
1470+
`final`. Without `receiver_adaptor` and `tag_invoke`, receiver adaptors
1471+
are easily written using implementation inheritance.
14661472

14671473
<b>Enhancements:</b>
14681474

@@ -5023,10 +5029,6 @@ namespace std::execution {
50235029
inline constexpr start_detached_t start_detached{};
50245030

50255031
// [exec.utils], sender and receiver utilities
5026-
// [exec.utils.rcvr.adptr]
5027-
template&lt;<i>class-type</i> Derived, receiver Base = <i>unspecified</i>>
5028-
class receiver_adaptor;
5029-
50305032
// [exec.utils.cmplsigs]
50315033
template&lt;class Fn>
50325034
concept <i>completion-signature</i> = <i>// exposition only</i>
@@ -5425,6 +5427,8 @@ enum class forward_progress_guarantee {
54255427
receiver&lt;Rcvr> && <i>has-completions</i>&lt;Rcvr, Completions>;
54265428
</pre>
54275429

5430+
2. Class types that are `final` do not model the `receiver` concept.
5431+
54285432
3. Let `rcvr` be a receiver and let `op_state` be an operation state associated
54295433
with an asynchronous operation created by connecting `rcvr` with a sender. Let
54305434
`token` be a stop token equal to `get_stop_token(get_env(rcvr))`. `token` shall
@@ -6848,7 +6852,8 @@ template&lt;class Domain, class Tag, sender Sndr, class... Args>
68486852
3. Let <i>`receiver-type`</i> denote the following class:
68496853

68506854
<pre highlight="c++">
6851-
struct <i>receiver-type</i> : receiver_adaptor&lt;<i>receiver-type</i>> {
6855+
struct <i>receiver-type</i> {
6856+
using receiver_concept = receiver_t;
68526857
<i>state-type</i>* <i>state</i>; // exposition only
68536858

68546859
Rcvr&& base() && noexcept { return std::move(<i>state</i>-><i>rcvr</i>); }
@@ -6864,6 +6869,19 @@ template&lt;class Domain, class Tag, sender Sndr, class... Args>
68646869
},
68656870
<i>state</i>-><i>async-result</i>);
68666871
}
6872+
6873+
template&lt;class Error>
6874+
void set_error(Error&& err) && noexcept {
6875+
execution::set_error(std::move(<i>state</i>-><i>rcvr</i>), std::forward&lt;Error>(err));
6876+
}
6877+
6878+
void set_stopped() && noexcept {
6879+
execution::set_stopped(std::move(<i>state</i>-><i>rcvr</i>));
6880+
}
6881+
6882+
decltype(auto) get_env() const noexcept {
6883+
return <i>FWD-ENV</i>(execution::get_env(<i>state</i>-><i>rcvr</i>));
6884+
}
68676885
};
68686886
</pre>
68696887

@@ -7010,12 +7028,13 @@ template&lt;class Domain, class Tag, sender Sndr, class... Args>
70107028

70117029
<pre highlight="c++">
70127030
template&lt;class Rcvr, class Env>
7013-
struct <i>receiver2</i> : receiver_adaptor&lt;<i>receiver2</i>&lt;Rcvr, Env>, Rcvr> {
7031+
struct <i>receiver2</i> : Rcvr {
70147032
explicit <i>receiver2</i>(Rcvr rcvr, Env env)
7015-
: <i>receiver2</i>::receiver_adaptor{std::move(rcvr)}, env(std::move(env)) {}
7033+
: Rcvr(std::move(rcvr)), env(std::move(env)) {}
70167034

70177035
auto get_env() const noexcept {
7018-
return <i>JOIN-ENV</i>(env, <i>FWD-ENV</i>(execution::get_env(this->base())));
7036+
const Rcvr& rcvr = *this;
7037+
return <i>JOIN-ENV</i>(env, <i>FWD-ENV</i>(execution::get_env(rcvr)));
70197038
}
70207039

70217040
Env env; // exposition only
@@ -8238,147 +8257,6 @@ template&lt;class Domain, class Tag, sender Sndr, class... Args>
82388257

82398258
## Sender/receiver utilities <b>[exec.utils]</b> ## {#spec-execution.snd_rec_utils}
82408259

8241-
### `execution::receiver_adaptor` <b>[exec.utils.rcvr.adptr]</b> ### {#spec-execution.snd_rec_utils.rcvr_adptr}
8242-
8243-
<pre highlight="c++">
8244-
template&lt;<i>class-type</i> Derived, receiver Base = <i>unspecified</i>>
8245-
class receiver_adaptor;
8246-
</pre>
8247-
8248-
1. `receiver_adaptor` simplifies the implementation of one receiver type in
8249-
terms of another. It defines named member functions that forward to
8250-
identically named members in the derived type if they exist, and to the
8251-
adapted receiver otherwise.
8252-
8253-
2. Let <code><i>HAS-BASE</i></code> be `false` if `Base` is an alias for the
8254-
unspecified default template argument; otherwise, it is `true`.
8255-
8256-
3. `receiver_adaptor<Derived, Base>` is as follows:
8257-
8258-
<pre highlight="c++">
8259-
template&lt;<i>class-type</i> Derived, receiver Base = <i>unspecified</i>>
8260-
class receiver_adaptor {
8261-
public:
8262-
using receiver_concept = receiver_t;
8263-
8264-
// Constructors
8265-
receiver_adaptor() = default;
8266-
template&lt;class B>
8267-
requires <i>HAS-BASE</i> && constructible_from&lt;Base, B>
8268-
explicit receiver_adaptor(B&& b) : <i>base-rcvr</i>(std::forward&lt;B>(b)) {}
8269-
8270-
// Member functions
8271-
template&lt;class... Args>
8272-
void set_value(Args&&... args) && noexcept;
8273-
8274-
template&lt;class Error>
8275-
void set_error(Error&& err) && noexcept;
8276-
8277-
void set_stopped() && noexcept;
8278-
8279-
decltype(auto) get_env() const noexcept {
8280-
return execution::get_env(<i>get-base</i>());
8281-
}
8282-
8283-
private:
8284-
friend Derived;
8285-
8286-
// Private member functions
8287-
template&lt;class Self>
8288-
decltype(auto) <i>get-base</i>(this Self&& self) noexcept; <i>// exposition only</i>
8289-
8290-
template&lt;class Self>
8291-
decltype(auto) base(this Self&& self) noexcept requires <i>HAS-BASE</i>;
8292-
8293-
Base <i>base-rcvr</i>; // exposition only, present if and only if <i>HAS-BASE</i> is true
8294-
};
8295-
</pre>
8296-
8297-
4. [<i>Note:</i> The `Derived` template parameter denotes a class type that is
8298-
incomplete when `receiver_adaptor` is instantiated.]
8299-
8300-
5. [<i>Example:</i>
8301-
<pre highlight="c++">
8302-
using _int_completion =
8303-
completion_signatures&lt;set_value_t(int)>;
8304-
8305-
template&lt;receiver_of&lt;_int_completion> Rcvr>
8306-
struct my_receiver
8307-
: receiver_adaptor&lt;my_receiver&lt;Rcvr>, Rcvr> {
8308-
explicit my_receiver(Rcvr r)
8309-
: receiver_adaptor&lt;my_receiver, Rcvr>(std::move(r)) {}
8310-
8311-
void set_value() && noexcept {
8312-
std::execution::set_value(std::move(*this).base(), 42);
8313-
}
8314-
};
8315-
</pre>
8316-
-- <i>end example</i>]
8317-
8318-
#### Member functions <b>[exec.utils.rcvr.adptr.members]</b> #### {#spec-execution.snd_rec_utils.receiver_adaptor.members}
8319-
8320-
<pre highlight="c++">
8321-
template&lt;class... Args>
8322-
void set_value(Args&&... args) && noexcept;
8323-
</pre>
8324-
8325-
1. Let <i>`e`</i> be the expression
8326-
<code>execution::set_value(std::move(<i>get-base</i>()), std::forward&lt;Args>(args)...)</code>.
8327-
8328-
2. <i>Constraints:</i> <i>`e`</i> is a well-formed expression.
8329-
8330-
3. <i>Effects:</i> Equivalent to <i>`e`</i>.
8331-
8332-
<pre highlight="c++">
8333-
template&lt;class Error>
8334-
void set_error(Error&& err) && noexcept;
8335-
</pre>
8336-
8337-
1. Let <i>`e`</i> be the expression
8338-
<code>execution::set_error(std::move(<i>get-base</i>()), std::forward&lt;Error>(err))</code>.
8339-
8340-
2. <i>Constraints:</i> <i>`e`</i> is a well-formed expression.
8341-
8342-
3. <i>Effects:</i> Equivalent to <i>`e`</i>.
8343-
8344-
<pre highlight="c++">
8345-
void set_stopped() && noexcept;
8346-
</pre>
8347-
8348-
1. Let <i>`e`</i> be the expression
8349-
<code>execution::set_stopped(std::move(<i>get-base</i>()))</code>.
8350-
8351-
2. <i>Constraints:</i> <i>`e`</i> is a well-formed expression.
8352-
8353-
3. <i>Effects:</i> Equivalent to <i>`e`</i>.
8354-
8355-
<pre highlight="c++">
8356-
template&lt;class Self>
8357-
decltype(auto) <i>get-base</i>(this Self&& self) noexcept;
8358-
</pre>
8359-
8360-
1. Let <i>`e`</i> be the expression
8361-
<code>std::forward_like&lt;Self>((Derived&) self).base()</code> if that expression
8362-
is well-formed; otherwise, it is
8363-
<code>std::forward_like&lt;Self>((receiver_adaptor&) self).base()</code>.
8364-
<span class="wg21note">The C-style casts are to disable accessibility checks.</span>
8365-
8366-
2. <i>Mandates:</i> `is_base_of_v<receiver_adaptor, Derived>` is `true` and <i>`e`</i>
8367-
is a well-formed expression.
8368-
8369-
3. <i>Returns:</i> <i>`e`</i>.
8370-
8371-
<pre highlight="c++">
8372-
template&lt;class Self>
8373-
decltype(auto) base(this Self&& self) noexcept requires <i>HAS-BASE</i>;
8374-
</pre>
8375-
8376-
1. Let <i>`e`</i> be the expression
8377-
<code>std::forward_like&lt;Self>((receiver_adaptor&) self).<i>base-rcvr</i></code>.
8378-
<span class="wg21note">The C-style cast is to disable accessibility checks.</span>
8379-
8380-
3. <i>Returns:</i> <code>(<i>e</i>)</code>.
8381-
83828260
### `execution::completion_signatures` <b>[exec.utils.cmplsigs]</b> ### {#spec-execution.snd_rec_utils.completion_sigs}
83838261

83848262
1. `completion_signatures` is a type that encodes a set of completion signatures

0 commit comments

Comments
 (0)