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 eachTs
is eitherset_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 eachTs
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 isEach 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
(andexecution::start
for the operation) but you also have to manually code the type transformations on the completion signatures via theexecution::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
orexecution::when_all
.