I'm looking at the reference implementation of P2300 (the senders and receivers proposal).
I'm having trouble understanding some of the code:
namespace __compl_sigs {
template <same_as<set_value_t> _Tag, class _Ty = __q<__types>, class... _Args>
__types<__minvoke<_Ty, _Args...>> __test(_Tag (*)(_Args...));
template <same_as<set_error_t> _Tag, class _Ty = __q<__types>, class _Error>
__types<__minvoke<_Ty, _Error>> __test(_Tag (*)(_Error));
template <same_as<set_stopped_t> _Tag, class _Ty = __q<__types>>
__types<__minvoke<_Ty>> __test(_Tag (*)());
template <class, class = void>
__types<> __test(...);
template <class _Tag, class _Ty = void, class... _Args>
void __test(_Tag (*)(_Args...) noexcept) = delete;
template <class _Sig>
concept __completion_signature = __typename<decltype(__compl_sigs::__test((_Sig*) nullptr))>;
} // namespace __compl_sigs
using __compl_sigs::__completion_signature;
// [...]
template <__compl_sigs::__completion_signature... _Sigs>
struct completion_signatures {
// Uncomment this to see where completion_signatures is
// erroneously getting instantiated:
//static_assert(sizeof...(_Sigs) == -1u);
};
Fundamentally, can someone give me an example for a sender and what __types<__minvoke<_Ty, _Args...>>
, __types<__minvoke<_Ty, _Error>>
and __types<__minvoke<_Ty>>
actually mean? I understand that they relate to set_value
, set_error
and set_stopped
.
Finally, what is the use for completion_signatures
?
completion_signatures<Ts...>
shall be a type list where each Ts
is either
set_value_t(Args...)
set_error_t(E)
set_stopped_t()
What you see in the implementation is, that a concept __completion_signature
is defined such that each Ts
of matches one of those forms. Otherwise, you cannot instantiate this template class. Note, that you are missing the definition of the __typename
concept in your snippet, which is
template <class... _Ts>
concept __typename = requires { typename __types<_Ts...>; };
Each sender defines at least two methods
execution::connect(sender, receiver) -> operation
execution::get_completion_signatures(sender, env) -> completion_signatures<...>
This constrained type list describes the possible completions of the async operation that results from the connect method.
Whenever you define a custom sender in P2300, you not only code the async code via the CPOs execution::connect
(and execution::start
for the operation) but you also have to manually code the type transformations on the completion signatures via the execution::get_completion_signatures
CPO.
Unfortunately, it is not possible, or feasible, to compute the completion signatures automatically. Knowing the set of possible completions is necessary to store the results in intermediate containers within algorithms, such as execution::let_value
or execution::when_all
.