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>>>;