33 Execution control library [exec]

33.9 Senders [exec.snd]

33.9.3 Sender concepts [exec.snd.concepts]

The sender concept defines the requirements for a sender type ([exec.async.ops]).
The sender_in concept defines the requirements for a sender type that can create asynchronous operations given an associated environment type.
The sender_to concept defines the requirements for a sender type that can connect with a specific receiver type.
The get_env customization point object is used to access a sender's associated attributes.
The connect customization point object is used to connect ([exec.async.ops]) a sender and a receiver to produce an operation state.
namespace std::execution { template<auto> concept is-constant = true; // exposition only template<class Sndr> concept is-sender = // exposition only derived_from<typename Sndr::sender_concept, sender_t>; template<class Sndr> concept enable-sender = // exposition only is-sender<Sndr> || is-awaitable<Sndr, env-promise<env<>>>; // [exec.awaitable] template<class Sndr> inline constexpr bool enable_sender = enable-sender<Sndr>; template<class Sndr> consteval bool is-dependent-sender-helper() try { // exposition only get_completion_signatures<Sndr>(); return false; } catch (dependent_sender_error&) { return true; } template<class Sndr> concept sender = enable_sender<remove_cvref_t<Sndr>> && requires (const remove_cvref_t<Sndr>& sndr) { { get_env(sndr) } -> queryable; } && move_constructible<remove_cvref_t<Sndr>> && constructible_from<remove_cvref_t<Sndr>, Sndr>; template<class Sndr, class... Env> concept sender_in = sender<Sndr> && (sizeof...(Env) <= 1) && (queryable<Env> &&...) && is-constant<get_completion_signatures<Sndr, Env...>()>; template<class Sndr> concept dependent_sender = sender<Sndr> && bool_constant<is-dependent-sender-helper<Sndr>()>::value; template<class Sndr, class Rcvr> concept sender_to = sender_in<Sndr, env_of_t<Rcvr>> && receiver_of<Rcvr, completion_signatures_of_t<Sndr, env_of_t<Rcvr>>> && requires (Sndr&& sndr, Rcvr&& rcvr) { connect(std::forward<Sndr>(sndr), std::forward<Rcvr>(rcvr)); }; }
For a type Sndr, if sender<Sndr> is true and dependent_sender<Sndr> is false, then Sndr is a non-dependent sender ([exec.async.ops]).
Given a subexpression sndr, let Sndr be decltype((sndr)) and let rcvr be a receiver with an associated environment whose type is Env.
A completion operation is a permissible completion for Sndr and Env if its completion signature appears in the argument list of the specialization of completion_signatures denoted by completion_signatures_of_t<Sndr, Env>.
Sndr and Env model sender_in<Sndr, Env> if all the completion operations that are potentially evaluated by connecting sndr to rcvr and starting the resulting operation state are permissible completions for Sndr and Env.
Remarks: Pursuant to [namespace.std], users may specialize enable_sender to true for cv-unqualified program-defined types that model sender, and false for types that do not.
Such specializations shall be usable in constant expressions ([expr.const]) and have type const bool.
The exposition-only concepts sender-of and sender-in-of define the requirements for a sender type that completes with a given unique set of value result types.
namespace std::execution { template<class... As> using value-signature = set_value_t(As...); // exposition only template<class Sndr, class SetValue, class... Env> concept sender-in-of-impl = // exposition only sender_in<Sndr, Env...> && MATCHING-SIG(SetValue, // see [exec.general] gather-signatures<set_value_t, // see [exec.cmplsig] completion_signatures_of_t<Sndr, Env...>, value-signature, type_identity_t>); template<class Sndr, class Env, class... Values> concept sender-in-of = // exposition only sender-in-of-impl<Sndr, set_value_t(Values...), Env>; template<class Sndr, class... Values> concept sender-of = // exposition only sender-in-of-impl<Sndr, set_value_t(Values...)>; }
Let sndr be an expression such that decltype((sndr)) is Sndr.
The type tag_of_t<Sndr> is as follows:
  • If the declaration auto&& [tag, data, ...children] = sndr; would be well-formed, tag_of_t<Sndr> is an alias for decltype(auto(tag)).
  • Otherwise, tag_of_t<Sndr> is ill-formed.
Let sender-for be an exposition-only concept defined as follows: namespace std::execution { template<class Sndr, class Tag> concept sender-for = sender<Sndr> && same_as<tag_of_t<Sndr>, Tag>; }
For a type T, SET-VALUE-SIG(T) denotes the type set_value_t() if T is cv void; otherwise, it denotes the type set_value_t(T).
Library-provided sender types
  • always expose an overload of a member connect that accepts an rvalue sender and
  • only expose an overload of a member connect that accepts an lvalue sender if they model copy_constructible.