2020// include these after __execution_fwd.hpp
2121#include " __completion_signatures_of.hpp"
2222#include " __connect_awaitable.hpp"
23- #include " __debug.hpp"
2423#include " __meta.hpp"
25- #include " __operation_states.hpp"
2624#include " __tag_invoke.hpp"
2725#include " __type_traits.hpp"
2826
@@ -31,148 +29,140 @@ namespace STDEXEC {
3129 // [execution.senders.connect]
3230 namespace __connect {
3331 template <class _Sender , class _Receiver >
34- using __tfx_sender = __mmemoize_q<transform_sender_result_t , _Sender, env_of_t <_Receiver>>;
32+ using __tfx_sender_t = __mmemoize_q<transform_sender_result_t , _Sender, env_of_t <_Receiver>>;
3533
3634 template <class _Sender , class _Receiver >
37- using __member_result_t = decltype (__declval<_Sender>().connect(__declval<_Receiver>()));
35+ concept __with_static_member =
36+ requires (__declfn_t <_Sender&&> __sndr, __declfn_t <_Receiver&&> __rcvr) {
37+ STDEXEC_REMOVE_REFERENCE (_Sender)::static_connect (__sndr (), __rcvr ());
38+ };
3839
3940 template <class _Sender , class _Receiver >
40- using __static_member_result_t = //
41- decltype (STDEXEC_REMOVE_REFERENCE(_Sender) //
42- ::static_connect (__declval<_Sender>(), __declval<_Receiver>()));
41+ concept __with_member = //
42+ requires (__declfn_t <_Sender&&> __sndr, __declfn_t <_Receiver&&> __rcvr) {
43+ __sndr ().connect (__rcvr ());
44+ };
4345
4446 template <class _Sender , class _Receiver >
45- concept __with_member = __minvocable_q<__member_result_t , _Sender, _Receiver>;
46-
47- template <class _Sender , class _Receiver >
48- concept __with_static_member = __minvocable_q<__static_member_result_t , _Sender, _Receiver>;
47+ concept __with_co_await = __awaitable<_Sender, __connect_await::__promise<_Receiver>>;
4948
5049 template <class _Sender , class _Receiver >
5150 concept __with_legacy_tag_invoke = tag_invocable<connect_t , _Sender, _Receiver>;
5251
5352 template <class _Sender , class _Receiver >
54- concept __with_co_await = __callable<__connect_awaitable_t , _Sender, _Receiver>;
53+ concept __with_any_connect = __with_static_member<_Sender, _Receiver>
54+ || __with_member<_Sender, _Receiver>
55+ || __with_co_await<_Sender, _Receiver>
56+ || __with_legacy_tag_invoke<_Sender, _Receiver>;
5557
5658 template <class _Sender , class _Receiver >
57- struct _NO_USABLE_CONNECT_CUSTOMIZATION_FOUND_ {
58- constexpr void operator ()() const noexcept = delete ;
59+ concept __connects_to = requires ( __declfn_t <_Sender&&> __sndr, __declfn_t <_Receiver&> __rcvr) {
60+ { transform_sender ( __sndr (), get_env ( __rcvr ())) } -> __with_any_connect<_Receiver> ;
5961 };
6062
63+ #define STDEXEC_DECLFN_FOR (_EXPR ) __declfn_t <decltype (_EXPR), noexcept (_EXPR)>
64+
65+ // A variable template whose type is a function pointer such that the
66+ // return type and noexcept-ness depend on whether _Sender can be connected
67+ // to _Receiver via any of the supported customization mechanisms.
68+ template <class _Sender , class _Receiver , bool _NothrowTransform>
69+ extern __declfn_t <void > __declfn_v;
70+
71+ template <class _Sender , class _Receiver >
72+ requires __with_static_member<_Sender, _Receiver>
73+ extern STDEXEC_DECLFN_FOR (STDEXEC_REMOVE_REFERENCE(_Sender)::static_connect(
74+ __declval<_Sender>(),
75+ __declval<_Receiver>())) __declfn_v<_Sender, _Receiver, true>;
76+
77+ template <class _Sender , class _Receiver >
78+ requires __with_static_member<_Sender, _Receiver>
79+ extern __declfn_t <
80+ decltype (STDEXEC_REMOVE_REFERENCE(
81+ _Sender)::static_connect(__declval<_Sender>(), __declval<_Receiver>())),
82+ false
83+ >
84+ __declfn_v<_Sender, _Receiver, false >;
85+
86+ template <class _Sender , class _Receiver >
87+ requires __with_static_member<_Sender, _Receiver> //
88+ || __with_member<_Sender, _Receiver>
89+ extern STDEXEC_DECLFN_FOR (__declval<_Sender>().connect(__declval<_Receiver>()))
90+ __declfn_v<_Sender, _Receiver, true>;
91+
92+ template <class _Sender , class _Receiver >
93+ requires __with_static_member<_Sender, _Receiver> //
94+ || __with_member<_Sender, _Receiver>
95+ extern __declfn_t <decltype (__declval<_Sender>().connect(__declval<_Receiver>())), false >
96+ __declfn_v<_Sender, _Receiver, false >;
97+
98+ template <class _Sender , class _Receiver >
99+ requires __with_static_member<_Sender, _Receiver> //
100+ || __with_member<_Sender, _Receiver> //
101+ || __with_co_await<_Sender, _Receiver>
102+ extern STDEXEC_DECLFN_FOR (__connect_awaitable(__declval<_Sender>(), __declval<_Receiver>()))
103+ __declfn_v<_Sender, _Receiver, true>;
104+
105+ template <class _Sender , class _Receiver >
106+ requires __with_static_member<_Sender, _Receiver> //
107+ || __with_member<_Sender, _Receiver> //
108+ || __with_co_await<_Sender, _Receiver>
109+ extern __declfn_t <
110+ decltype (__connect_awaitable(__declval<_Sender>(), __declval<_Receiver>())),
111+ false
112+ >
113+ __declfn_v<_Sender, _Receiver, false>;
114+
115+ template <class _Sender , class _Receiver >
116+ requires __with_static_member<_Sender, _Receiver> //
117+ || __with_member<_Sender, _Receiver> //
118+ || __with_co_await<_Sender, _Receiver> //
119+ || __with_legacy_tag_invoke<_Sender, _Receiver>
120+ extern STDEXEC_DECLFN_FOR (tag_invoke(connect, __declval<_Sender>(), __declval<_Receiver>()))
121+ __declfn_v<_Sender, _Receiver, true>;
122+
123+ template <class _Sender , class _Receiver >
124+ requires __with_static_member<_Sender, _Receiver> //
125+ || __with_member<_Sender, _Receiver> //
126+ || __with_co_await<_Sender, _Receiver> //
127+ || __with_legacy_tag_invoke<_Sender, _Receiver>
128+ extern __declfn_t <tag_invoke_result_t <connect_t , _Sender, _Receiver>, false >
129+ __declfn_v<_Sender, _Receiver, false >;
130+
131+ #undef STDEXEC_DECLFN_FOR
132+
61133 // ///////////////////////////////////////////////////////////////////////////
62134 // connect_t
63135 struct connect_t {
64136 template <class _Sender , class _Receiver >
137+ using __declfn_t =
138+ decltype (__declfn_v<
139+ __call_result_t <transform_sender_t , _Sender, env_of_t <_Receiver>>,
140+ _Receiver,
141+ __nothrow_callable<transform_sender_t , _Sender, env_of_t <_Receiver>>
142+ >);
143+
144+ template <class _Sender , class _Receiver , class _DeclFn = __declfn_t <_Sender, _Receiver>>
145+ requires __connects_to<_Sender, _Receiver>
65146 STDEXEC_ATTRIBUTE (always_inline)
66- static constexpr auto __type_check_arguments () noexcept -> bool {
67- if constexpr (sender_in<_Sender, env_of_t <_Receiver>>) {
68- // Instantiate __debug_sender via completion_signatures_of_t to check that the actual
69- // completions match the expected completions.
70- using __checked_signatures
71- [[maybe_unused]] = completion_signatures_of_t <_Sender, env_of_t <_Receiver>>;
72- } else {
73- __diagnose_sender_concept_failure<__demangle_t <_Sender>, env_of_t <_Receiver>>();
74- }
75- return true ;
76- }
77-
78- template <class _OpState >
79- static constexpr void __check_operation_state () noexcept {
80- static_assert (operation_state<_OpState>, STDEXEC_ERROR_CANNOT_CONNECT_SENDER_TO_RECEIVER);
81- }
82-
83- template <class _Sender , class _Receiver >
84- static consteval auto __get_declfn () noexcept {
85- static_assert (sender<_Sender>, " The first argument to STDEXEC::connect must be a sender" );
86- if constexpr (!receiver<_Receiver>) {
87- static_assert (
88- __nothrow_move_constructible<__decay_t <_Receiver>>,
89- " Receivers must be nothrow move constructible" );
90- static_assert (
91- receiver<_Receiver>, " The second argument to STDEXEC::connect must be a receiver" );
92- }
93-
94- static_assert (sender_in<_Sender, env_of_t <_Receiver>>);
95- static_assert (__receiver_from<_Receiver, _Sender>);
96-
97- using _TfxSender = __tfx_sender<_Sender, _Receiver>;
98- constexpr bool _NothrowTfxSender =
99- __nothrow_callable<transform_sender_t , _Sender, env_of_t <_Receiver>>;
100-
101- #if STDEXEC_ENABLE_EXTRA_TYPE_CHECKING()
102- static_assert (__type_check_arguments<_TfxSender, _Receiver>());
103- #endif
104-
105- if constexpr (__with_static_member<_TfxSender, _Receiver>) {
106- using _Result = __static_member_result_t <_TfxSender, _Receiver>;
107- __check_operation_state<_Result>();
108- constexpr bool _Nothrow = _NothrowTfxSender
109- && noexcept (STDEXEC_REMOVE_REFERENCE (_TfxSender)::static_connect (
110- __declval<_TfxSender>(), __declval<_Receiver>()));
111- return __declfn<_Result, _Nothrow>();
112- } else if constexpr (__with_member<_TfxSender, _Receiver>) {
113- using _Result = __member_result_t <_TfxSender, _Receiver>;
114- __check_operation_state<_Result>();
115- constexpr bool _Nothrow = _NothrowTfxSender
116- && noexcept (__declval<_TfxSender>()
117- .connect (__declval<_Receiver>()));
118- return __declfn<_Result, _Nothrow>();
119- } else if constexpr (__with_co_await<_TfxSender, _Receiver>) {
120- using _Result = __call_result_t <__connect_awaitable_t , _TfxSender, _Receiver>;
121- return __declfn<_Result, false >();
122- } else if constexpr (__is_debug_env<env_of_t <_Receiver>>) {
123- using _Result = __debug::__opstate;
124- return __declfn<_Result, _NothrowTfxSender>();
125- } else {
126- return _NO_USABLE_CONNECT_CUSTOMIZATION_FOUND_<
127- _WITH_PRETTY_SENDER_<_TfxSender>,
128- _WITH_RECEIVER_ (_Receiver)
129- >();
130- }
131- }
132-
133- template <class _Sender , class _Receiver , auto _DeclFn = __get_declfn<_Sender, _Receiver>()>
134- requires __callable<__mtypeof<_DeclFn>>
135147 constexpr auto operator ()(_Sender&& __sndr, _Receiver&& __rcvr) const
136- noexcept (noexcept (_DeclFn())) -> decltype(_DeclFn()) {
137- using _TfxSender = __tfx_sender<_Sender, _Receiver>;
138- auto && __env = get_env (__rcvr);
139-
140- if constexpr (__with_static_member<_TfxSender, _Receiver>) {
141- auto && __tfx_sndr = transform_sender (static_cast <_Sender&&>(__sndr), __env);
142- return STDEXEC_REMOVE_REFERENCE (_TfxSender)::static_connect (
143- static_cast <_TfxSender&&>(__tfx_sndr), static_cast <_Receiver&&>(__rcvr));
144- } else if constexpr (__with_member<_TfxSender, _Receiver>) { // NOLINT(bugprone-branch-clone)
145- auto && __tfx_sndr = transform_sender (static_cast <_Sender&&>(__sndr), __env);
146- return static_cast <_TfxSender&&>(__tfx_sndr).connect (static_cast <_Receiver&&>(__rcvr));
147- } else if constexpr (__with_co_await<_TfxSender, _Receiver>) {
148- auto && __tfx_sndr = transform_sender (static_cast <_Sender&&>(__sndr), __env);
148+ noexcept (__nothrow_callable<_DeclFn>) -> __call_result_t<_DeclFn> {
149+ auto && __new_sndr = transform_sender (static_cast <_Sender&&>(__sndr), get_env (__rcvr));
150+ using __new_sndr_t = decltype (__new_sndr);
151+
152+ if constexpr (__with_static_member<__new_sndr_t , _Receiver>) {
153+ return STDEXEC_REMOVE_REFERENCE (__new_sndr_t )::static_connect (
154+ static_cast <__new_sndr_t &&>(__new_sndr), static_cast <_Receiver&&>(__rcvr));
155+ } else if constexpr (__with_member<__new_sndr_t , _Receiver>) {
156+ return static_cast <__new_sndr_t &&>(__new_sndr).connect (static_cast <_Receiver&&>(__rcvr));
157+ } else if constexpr (__with_co_await<__new_sndr_t , _Receiver>) {
149158 return __connect_awaitable (
150- static_cast <_TfxSender &&>(__tfx_sndr ), static_cast <_Receiver&&>(__rcvr));
159+ static_cast <__new_sndr_t &&>(__new_sndr ), static_cast <_Receiver&&>(__rcvr));
151160 } else {
152- // This should generate an instantiation backtrace that contains useful
153- // debugging information.
154- auto && __tfx_sndr = transform_sender (static_cast <_Sender&&>(__sndr), __env);
155- return static_cast <_TfxSender&&>(__tfx_sndr).connect (static_cast <_Receiver&&>(__rcvr));
161+ return tag_invoke (
162+ *this , static_cast <__new_sndr_t &&>(__new_sndr), static_cast <_Receiver&&>(__rcvr));
156163 }
157164 }
158165
159- template <class _Sender , class _Receiver , auto _DeclFn = __get_declfn<_Sender, _Receiver>()>
160- requires __callable<__mtypeof<_DeclFn>>
161- || __with_legacy_tag_invoke<__tfx_sender<_Sender, _Receiver>, _Receiver>
162- [[deprecated(" the use of tag_invoke for connect is deprecated" )]]
163- constexpr auto operator ()(_Sender&& __sndr, _Receiver&& __rcvr) const noexcept (
164- __nothrow_callable<transform_sender_t , _Sender, env_of_t <_Receiver>>
165- && nothrow_tag_invocable<connect_t , __tfx_sender<_Sender, _Receiver>, _Receiver>)
166- -> tag_invoke_result_t<connect_t, __tfx_sender<_Sender, _Receiver>, _Receiver> {
167- using _TfxSender = __tfx_sender<_Sender, _Receiver>;
168- using _Result = tag_invoke_result_t <connect_t , _TfxSender, _Receiver>;
169- __check_operation_state<_Result>();
170- auto && __env = get_env (__rcvr);
171- auto && __tfx_sndr = transform_sender (static_cast <_Sender&&>(__sndr), __env);
172- return tag_invoke (
173- connect_t (), static_cast <_TfxSender&&>(__tfx_sndr), static_cast <_Receiver&&>(__rcvr));
174- }
175-
176166 static constexpr auto query (forwarding_query_t ) noexcept -> bool {
177167 return false ;
178168 }
0 commit comments