Skip to content

Commit 78963fe

Browse files
committed
Relax overload resolution of any_receiver's completion functions
1 parent 184a8ab commit 78963fe

File tree

3 files changed

+54
-32
lines changed

3 files changed

+54
-32
lines changed

include/exec/any_sender_of.hpp

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -440,9 +440,7 @@ namespace exec {
440440
(*__other.__vtable_)(__copy_construct, this, __other);
441441
}
442442

443-
auto operator=(const __t& __other) -> __t&
444-
requires(_Copyable)
445-
{
443+
auto operator=(const __t& __other) -> __t& requires(_Copyable) {
446444
if (&__other != this) {
447445
__t tmp(__other);
448446
*this = std::move(tmp);
@@ -520,7 +518,8 @@ namespace exec {
520518
}
521519

522520
template <class _Tp>
523-
STDEXEC_MEMFN_DECL(void __move_construct)(this __mtype<_Tp>, __t& __self, __t&& __other) noexcept {
521+
STDEXEC_MEMFN_DECL(
522+
void __move_construct)(this __mtype<_Tp>, __t& __self, __t&& __other) noexcept {
524523
if (!__other.__object_pointer_) {
525524
return;
526525
}
@@ -540,8 +539,7 @@ namespace exec {
540539

541540
template <class _Tp>
542541
requires _Copyable
543-
STDEXEC_MEMFN_DECL(
544-
void __copy_construct)(this __mtype<_Tp>, __t& __self, const __t& __other) {
542+
STDEXEC_MEMFN_DECL(void __copy_construct)(this __mtype<_Tp>, __t& __self, const __t& __other) {
545543
if (!__other.__object_pointer_) {
546544
return;
547545
}
@@ -563,7 +561,8 @@ namespace exec {
563561

564562
struct __empty_vtable {
565563
template <class _Sender>
566-
STDEXEC_MEMFN_DECL(auto __create_vtable)(this __mtype<__empty_vtable>, __mtype<_Sender>) noexcept
564+
STDEXEC_MEMFN_DECL(
565+
auto __create_vtable)(this __mtype<__empty_vtable>, __mtype<_Sender>) noexcept
567566
-> const __empty_vtable* {
568567
static const __empty_vtable __vtable_{};
569568
return &__vtable_;
@@ -616,11 +615,12 @@ namespace exec {
616615
, public __query_vfun<_Queries>... {
617616
public:
618617
using __query_vfun<_Queries>::operator()...;
618+
using __any_::__rcvr_vfun<_Sigs>::operator()...;
619619

620620
private:
621621
template <class _Rcvr>
622622
requires receiver_of<_Rcvr, completion_signatures<_Sigs...>>
623-
&& (__callable<__query_vfun_fn<_Rcvr>, _Queries> && ...)
623+
&& (__callable<__query_vfun_fn<_Rcvr>, _Queries> && ...)
624624
STDEXEC_MEMFN_DECL(
625625
auto __create_vtable)(this __mtype<__t>, __mtype<_Rcvr>) noexcept -> const __t* {
626626
static const __t __vtable_{
@@ -675,33 +675,30 @@ namespace exec {
675675
}
676676

677677
template <class... _As>
678-
requires __one_of<set_value_t(_As...), _Sigs...>
678+
requires __callable<__vtable_t, void*, set_value_t, _As...>
679679
void set_value(_As&&... __as) noexcept {
680-
const __any_::__rcvr_vfun<set_value_t(_As...)>* __vfun = __env_.__vtable_;
681-
(*__vfun->__complete_)(__env_.__rcvr_, static_cast<_As&&>(__as)...);
680+
(*__env_.__vtable_)(__env_.__rcvr_, set_value_t(), static_cast<_As&&>(__as)...);
682681
}
683682

684683
template <class _Error>
685-
requires __one_of<set_error_t(_Error), _Sigs...>
684+
requires __callable<__vtable_t, void*, set_error_t, _Error>
686685
void set_error(_Error&& __err) noexcept {
687-
const __any_::__rcvr_vfun<set_error_t(_Error)>* __vfun = __env_.__vtable_;
688-
(*__vfun->__complete_)(__env_.__rcvr_, static_cast<_Error&&>(__err));
686+
(*__env_.__vtable_)(__env_.__rcvr_, set_error_t(), static_cast<_Error&&>(__err));
689687
}
690688

691689
void set_stopped() noexcept
692-
requires __one_of<set_stopped_t(), _Sigs...>
690+
requires __callable<__vtable_t, void*, set_stopped_t>
693691
{
694-
const __any_::__rcvr_vfun<set_stopped_t()>* __vfun = __env_.__vtable_;
695-
(*__vfun->__complete_)(__env_.__rcvr_);
692+
(*__env_.__vtable_)(__env_.__rcvr_, set_stopped_t());
696693
}
697694

698695
auto get_env() const noexcept -> const __env_t& {
699696
return __env_;
700697
}
701698
};
702699

703-
auto __test_never_stop_token(
704-
get_stop_token_t (*)(never_stop_token (*)() noexcept)) -> __mbool<true>;
700+
auto __test_never_stop_token(get_stop_token_t (*)(never_stop_token (*)() noexcept))
701+
-> __mbool<true>;
705702

706703
template <class _Tag, class _Ret, class... _As>
707704
auto __test_never_stop_token(_Tag (*)(_Ret (*)(_As...) noexcept)) -> __mbool<false>;
@@ -783,7 +780,8 @@ namespace exec {
783780

784781
private:
785782
template <class _Op>
786-
STDEXEC_MEMFN_DECL(auto __create_vtable)(this __mtype<__operation_vtable>, __mtype<_Op>) noexcept
783+
STDEXEC_MEMFN_DECL(
784+
auto __create_vtable)(this __mtype<__operation_vtable>, __mtype<_Op>) noexcept
787785
-> const __operation_vtable* {
788786
static __operation_vtable __vtable{[](void* __object_pointer) noexcept -> void {
789787
STDEXEC_ASSERT(__object_pointer);
@@ -831,8 +829,7 @@ namespace exec {
831829

832830
template <same_as<__t> _Self, class _Item>
833831
requires __callable<set_next_t, _Receiver&, _Item>
834-
STDEXEC_MEMFN_DECL(
835-
auto set_next)(this _Self& __self, _Item&& __item) noexcept
832+
STDEXEC_MEMFN_DECL(auto set_next)(this _Self& __self, _Item&& __item) noexcept
836833
-> __call_result_t<set_next_t, _Receiver&, _Item> {
837834
return exec::set_next(__self.__op_->__rcvr_, static_cast<_Item&&>(__item));
838835
}
@@ -961,7 +958,9 @@ namespace exec {
961958
__immovable_operation_storage (*__connect_)(void*, __receiver_ref_t);
962959
private:
963960
template <sender_to<__receiver_ref_t> _Sender>
964-
STDEXEC_MEMFN_DECL(auto __create_vtable)(this __mtype<__vtable>, __mtype<_Sender>) noexcept -> const __vtable* {
961+
STDEXEC_MEMFN_DECL(
962+
auto
963+
__create_vtable)(this __mtype<__vtable>, __mtype<_Sender>) noexcept -> const __vtable* {
965964
static const __vtable __vtable_{
966965
{*__create_vtable(__mtype<__query_vtable<_SenderQueries>>{}, __mtype<_Sender>{})},
967966
[](void* __object_pointer, __receiver_ref_t __receiver)
@@ -1083,7 +1082,9 @@ namespace exec {
10831082
}
10841083
private:
10851084
template <scheduler _Scheduler>
1086-
STDEXEC_MEMFN_DECL(auto __create_vtable)(this __mtype<__vtable>, __mtype<_Scheduler>) noexcept -> const __vtable* {
1085+
STDEXEC_MEMFN_DECL(
1086+
auto
1087+
__create_vtable)(this __mtype<__vtable>, __mtype<_Scheduler>) noexcept -> const __vtable* {
10871088
static const __vtable __vtable_{
10881089
{*__create_vtable(
10891090
__mtype<__query_vtable<_SchedulerQueries, false>>{}, __mtype<_Scheduler>{})},

include/stdexec/__detail/__receiver_ref.hpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,16 @@ namespace stdexec { namespace __any_ {
3030

3131
template <class _Tag, class... _Args>
3232
struct __rcvr_vfun<_Tag(_Args...)> {
33-
void (*__complete_)(void*, _Args&&...) noexcept;
33+
void (*__complete_)(void*, _Args...) noexcept;
3434

35-
void operator()(void* __obj, _Tag, _Args&&... __args) const noexcept {
35+
void operator()(void* __obj, _Tag, _Args... __args) const noexcept {
3636
__complete_(__obj, static_cast<_Args&&>(__args)...);
3737
}
3838
};
3939

4040
template <class _GetReceiver = std::identity, class _Obj, class _Tag, class... _Args>
4141
constexpr auto __rcvr_vfun_fn(_Obj*, _Tag (*)(_Args...)) noexcept {
42-
return +[](void* __ptr, _Args&&... __args) noexcept {
42+
return +[](void* __ptr, _Args... __args) noexcept {
4343
_Obj* __obj = static_cast<_Obj*>(__ptr);
4444
_Tag()(std::move(_GetReceiver()(*__obj)), static_cast<_Args&&>(__args)...);
4545
};
@@ -95,16 +95,20 @@ namespace stdexec { namespace __any_ {
9595
}
9696

9797
template <class... _As>
98+
requires __callable<__receiver_vtable_for<_Sigs, _Env>, void*, set_value_t, _As...>
9899
void set_value(_As&&... __as) noexcept {
99100
(*__vtable_)(__op_state_, set_value_t(), static_cast<_As&&>(__as)...);
100101
}
101102

102103
template <class _Error>
104+
requires __callable<__receiver_vtable_for<_Sigs, _Env>, void*, set_error_t, _Error>
103105
void set_error(_Error&& __err) noexcept {
104106
(*__vtable_)(__op_state_, set_error_t(), static_cast<_Error&&>(__err));
105107
}
106108

107-
void set_stopped() noexcept {
109+
void set_stopped() noexcept
110+
requires __callable<__receiver_vtable_for<_Sigs, _Env>, void*, set_stopped_t>
111+
{
108112
(*__vtable_)(__op_state_, set_stopped_t());
109113
}
110114

test/exec/test_any_sender.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ namespace {
3636
template <class T>
3737
// BUGBUG ambiguous!
3838
requires stdexec::tag_invocable<tag_t, T>
39-
auto operator()(T&& t) const
40-
noexcept(stdexec::nothrow_tag_invocable<tag_t, T>) -> stdexec::tag_invoke_result_t<tag_t, T> {
39+
auto operator()(T&& t) const noexcept(stdexec::nothrow_tag_invocable<tag_t, T>)
40+
-> stdexec::tag_invoke_result_t<tag_t, T> {
4141
return stdexec::tag_invoke(*this, static_cast<T&&>(t));
4242
}
4343
};
@@ -328,6 +328,23 @@ namespace {
328328
}
329329
}
330330

331+
template <class... Vals>
332+
using my_stoppable_sender_of =
333+
any_sender_of<set_value_t(Vals)..., set_error_t(std::exception_ptr), set_stopped_t()>;
334+
335+
TEST_CASE("any_sender uses overload rules for completion signatures", "[types][any_sender]") {
336+
auto split_sender = split(just(21));
337+
static_assert(sender_of<decltype(split_sender), set_error_t(const std::exception_ptr&)>);
338+
static_assert(sender_of<decltype(split_sender), set_value_t(const int&)>);
339+
my_stoppable_sender_of<int> sender = split_sender;
340+
341+
auto [value] = *sync_wait(std::move(sender));
342+
CHECK(value == 42);
343+
344+
sender = just(21) | then([&](int) -> int { throw 420; });
345+
CHECK_THROWS_AS(sync_wait(std::move(sender)), int);
346+
}
347+
331348
class stopped_token {
332349
private:
333350
bool stopped_{true};
@@ -686,8 +703,8 @@ namespace {
686703
return {{}, static_cast<R&&>(r)};
687704
}
688705

689-
auto
690-
query(ex::get_completion_scheduler_t<ex::set_value_t>) const noexcept -> counting_scheduler {
706+
auto query(ex::get_completion_scheduler_t<ex::set_value_t>) const noexcept
707+
-> counting_scheduler {
691708
return {};
692709
}
693710

0 commit comments

Comments
 (0)