![]() |
template<class S>
concept sender =
move_constructible<remove_cvref_t<S>> &&
!requires {
typename sender_traits<remove_cvref_t<S>>::__unspecialized; // exposition only
};
template<class S, class R>
concept sender_to =
sender<S> &&
receiver<R> &&
requires (S&& s, R&& r) {
execution::connect((S&&) s, (R&&) r);
};
None of these operations shall introduce data races as a result of concurrent invocations of those functions from different threads.
A sender type's destructor shall not block pending completion of the submitted function objects.
[Note: The ability to wait for completion of submitted function objects may be provided by the associated execution context. —end note]
A sender is typed if it declares what types
it sends through a receiver's channels. The typed_sender concept
is defined as:
template<template<template<class...> class Tuple, template<class...> class Variant> class>
struct has-value-types; // exposition only
template<template<class...> class Variant>
struct has-error-types; // exposition only
template<class S>
concept has-sender-types = // exposition only
requires {
typename has-value-types<S::template value_types>;
typename has-error-types<S::template error_types>;
typename bool_constant<S::sends_done>;
};
template<class S>
concept typed_sender =
sender<S> &&
has-sender-types<sender_traits<remove_cvref_t<S>>>;