![]() |
Home | Libraries | People | FAQ | More |
An executor adapter that records properties rather than applying them.
template< typename Executor, typename... Properties> class staging_executor
|
Name |
Description |
|---|---|
|
The type of executor that results from committing. |
|
|
The type of the target executor. |
|
Name |
Description |
|---|---|
|
Apply the recorded properties to the target. |
|
|
Apply the recorded properties and submit a function object. |
|
|
Obtain a reference to the target executor. |
|
|
Convert to an owning executor by committing. |
|
|
Record a preference. |
|
|
Query the recorded allocator property. |
|
|
query [static] |
Query the recorded blocking property. |
|
Record a property. |
|
|
staging_executor [constructor] |
Construct a staging executor for the specified target. |
|
Name |
Description |
|---|---|
|
Compare two staging executors for inequality. |
|
|
Compare two staging executors for equality. |
A staging_executor refers
to, or owns, a target executor. Calls to boost::asio::require
and boost::asio::prefer on a staging executor do not touch
the target. Instead, they return a new staging executor that records the
property at the end of a sequence. The recorded properties are applied together,
to the target itself, only when a function object is submitted using execute(),
or when the staging executor is committed to an ordinary executor.
This avoids producing a sequence of intermediate executors when several properties
are applied before a function object is submitted. The saving is greatest
when the target is a polymorphic executor such as any_io_executor,
where each intermediate result would otherwise be a newly constructed polymorphic
wrapper.
The Executor template parameter
determines whether the target is owned:
staging_executor<const E&> refers to an existing executor
object of type E, which
is not copied. It must not outlive that object. This is the type returned
by execution::stage for an lvalue.
staging_executor<E>
owns its target. This is the type returned by execution::stage for an rvalue, which is
moved rather than copied, so that an expression such as execution::stage(sock.get_executor()).require(...)
is valid within a single statement.
The Properties template parameter
pack holds the recorded properties, in the order in which they were requested.
A property that was required appears as the property's own type, such as
execution::blocking_t::never_t, and a property P
that was preferred appears as execution::prefer_only<P>.
The recorded properties are applied in request order: the first is applied
to the target, and each one after it to the result of the one before.
Each property is recorded under a key, which is the type the property is
queried as where it has one, such as execution::blocking_t
for execution::blocking_t::never_t, and the property's own type otherwise.
A preference keys to the same entry as the corresponding requirement. Recording
a property replaces the entry already holding its key, in the position that
entry was first recorded in, so the sequence holds at most one entry per
key. Only the last of the properties sharing a key is therefore applied,
and the order of the entries is the order in which their keys were first
requested.
A consequence is that the set of staging executor types that recording properties can reach is closed, which matters where a staging executor is reachable behind a polymorphic executor: such an executor applies every property it supports to every target it adopts, and adopts each result in turn.
A require is offered only
when the resulting sequence is valid when applied to the target in that order.
A preference that the target would not act upon, whether because it already
has the property or because it does not support it, returns the staging executor
unchanged.
A query that a recorded property answers is answered from the most recently recorded such property. All other queries are forwarded to the target.
The combinations that a polymorphic executor can apply to the executor it holds without constructing another polymorphic executor are recognised without regard to the order in which their entries were recorded, as the polymorphic executor applies the blocking requirement before the relationship preference in either case.
void post_to(const boost::asio::any_io_executor& ex, F f) { // No intermediate any_io_executor objects are created. boost::asio::prefer( boost::asio::require(execution::stage(ex), execution::blocking.never), execution::relationship.fork ).execute(std::move(f)); }
Header: boost/asio/execution/staging_executor.hpp
Convenience header: boost/asio/execution.hpp