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 eachTsis eitherset_value_t(Args...)set_error_t(E)set_stopped_t()What you see in the implementation is, that a concept
__completion_signatureis defined such that eachTsof matches one of those forms. Otherwise, you cannot instantiate this template class. Note, that you are missing the definition of the__typenameconcept in your snippet, which isEach sender defines at least two methods
execution::connect(sender, receiver) -> operationexecution::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::startfor the operation) but you also have to manually code the type transformations on the completion signatures via theexecution::get_completion_signaturesCPO.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_valueorexecution::when_all.