<table style="width:79%;">
<colgroup>
<col width="27%" />
<col width="51%" />
</colgroup>
<tbody>
<tr class="odd">
<td align="left">Title:</td>
<td align="left">A Unified Executors Proposal for C++</td>
</tr>
<tr class="even">
<td align="left">Authors:</td>
<td align="left">Jared Hoberock, jhoberock@nvidia.com</td>
</tr>
<tr class="odd">
<td align="left"></td>
<td align="left">Michael Garland, mgarland@nvidia.com</td>
</tr>
<tr class="even">
<td align="left"></td>
<td align="left">Chris Kohlhoff, chris@kohlhoff.com</td>
</tr>
<tr class="odd">
<td align="left"></td>
<td align="left">Chris Mysen, mysen@google.com</td>
</tr>
<tr class="even">
<td align="left"></td>
<td align="left">Carter Edwards, hcedwar@sandia.gov</td>
</tr>
<tr class="odd">
<td align="left"></td>
<td align="left">Gordon Brown, gordon@codeplay.com</td>
</tr>
<tr class="even">
<td align="left">Other Contributors:</td>
<td align="left">Hans Boehm, hboehm@google.com</td>
</tr>
<tr class="odd">
<td align="left"></td>
<td align="left">Thomas Heller, thom.heller@gmail.com</td>
</tr>
<tr class="even">
<td align="left"></td>
<td align="left">Lee Howes, lwh@fb.com</td>
</tr>
<tr class="odd">
<td align="left"></td>
<td align="left">Bryce Lelbach, brycelelbach@gmail.com</td>
</tr>
<tr class="even">
<td align="left"></td>
<td align="left">Hartmut Kaiser, hartmut.kaiser@gmail.com</td>
</tr>
<tr class="odd">
<td align="left"></td>
<td align="left">Bryce Lelbach, brycelelbach@gmail.com</td>
</tr>
<tr class="even">
<td align="left"></td>
<td align="left">Gor Nishanov, gorn@microsoft.com</td>
</tr>
<tr class="odd">
<td align="left"></td>
<td align="left">Thomas Rodgers, rodgert@twrodgers.com</td>
</tr>
<tr class="even">
<td align="left"></td>
<td align="left">David Hollman, dshollm@sandia.gov</td>
</tr>
<tr class="odd">
<td align="left"></td>
<td align="left">Michael Wong, michael@codeplay.com</td>
</tr>
<tr class="even">
<td align="left">Document Number:</td>
<td align="left">P0443R4</td>
</tr>
<tr class="odd">
<td align="left">Date:</td>
<td align="left">2017-11-22</td>
</tr>
<tr class="even">
<td align="left">Audience:</td>
<td align="left">SG1 - Concurrency and Parallelism</td>
</tr>
<tr class="odd">
<td align="left">Reply-to:</td>
<td align="left">sg1-exec@googlegroups.com</td>
</tr>
<tr class="even">
<td align="left">Abstract:</td>
<td align="left">This paper proposes a programming model for executors, which are modular components for creating execution. The design of this proposal is described in paper <a href="https://wg21.link/P0761">P0761</a>.</td>
</tr>
</tbody>
</table>
<h2 id="changelog"><span class="header-section-number">0.1</span> Changelog</h2>
<h3 id="revision-4"><span class="header-section-number">0.1.1</span> Revision 4</h3>
<ul>
<li>Specified the guarantees implied by <code>bulk_sequenced_execution</code>, <code>bulk_parallel_execution</code>, and <code>bulk_unsequenced_execution</code></li>
</ul>
<h3 id="revision-3"><span class="header-section-number">0.1.2</span> Revision 3</h3>
<ul>
<li>Introduced <code>execution::query()</code> for executor property introspection</li>
<li>Simplified the design of <code>execution::prefer()</code></li>
<li><code>oneway</code>, <code>twoway</code>, <code>single</code>, and <code>bulk</code> are now <code>require()</code>-only properties</li>
<li>Introduced properties allowing executors to opt into adaptations that add blocking semantics</li>
<li>Introduced properties describing the forward progress relationship between caller and agents</li>
<li>Various minor improvements to existing functionality based on prototyping</li>
</ul>
<h3 id="revision-2"><span class="header-section-number">0.1.3</span> Revision 2</h3>
<ul>
<li>Separated wording from explanatory prose, now contained in paper <a href="https://wg21.link/P0761">P0761</a></li>
<li>Applied the simplification proposed by paper <a href="https://wg21.link/P0688">P0688</a></li>
</ul>
<h3 id="revision-1"><span class="header-section-number">0.1.4</span> Revision 1</h3>
<ul>
<li>Executor category simplification</li>
<li>Specified executor customization points in detail</li>
<li>Introduced new fine-grained executor type traits
<ul>
<li>Detectors for execution functions</li>
<li>Traits for introspecting cross-cutting concerns
<ul>
<li>Introspection of mapping of agents to threads</li>
<li>Introspection of execution function blocking behavior</li>
</ul></li>
</ul></li>
<li>Allocator support for single agent execution functions</li>
<li>Renamed <code>thread_pool</code> to <code>static_thread_pool</code></li>
<li>New introduction</li>
</ul>
<h3 id="revision-0"><span class="header-section-number">0.1.5</span> Revision 0</h3>
<ul>
<li>Initial design</li>
</ul>
<h1 id="proposed-wording"><span class="header-section-number">1</span> Proposed Wording</h1>
<h3 id="header-execution-synopsis"><span class="header-section-number">1.0.1</span> Header <code>&lt;execution&gt;</code> synopsis</h3>
<pre><code>namespace std {
namespace experimental {
inline namespace concurrency_v2 {
namespace execution {

  // Directionality properties:

  constexpr struct oneway_t {} oneway;
  constexpr struct twoway_t {} twoway;
  constexpr struct then_t {} then;

  // Cardinality properties:

  constexpr struct single_t {} single;
  constexpr struct bulk_t {} bulk;

  // Blocking properties:

  constexpr struct possibly_blocking_t {} possibly_blocking;
  constexpr struct always_blocking_t {} always_blocking;
  constexpr struct never_blocking_t {} never_blocking;

  // Properties to allow adaptation of blocking and directionality:

  constexpr struct adaptable_blocking_t {} adaptable_blocking;
  constexpr struct not_adaptable_blocking_t {} not_adaptable_blocking;

  // Properties to indicate if submitted tasks represent continuations:

  constexpr struct not_continuation_t {} not_continuation;
  constexpr struct continuation_t {} continuation;

  // Properties to indicate likely task submission in the future:

  constexpr struct not_outstanding_work_t {} not_outstanding_work;
  constexpr struct outstanding_work_t {} outstanding_work;

  // Properties for caller execution forward progress guarantess:

  constexpr struct caller_weakly_parallel_execution_t {} caller_weakly_parallel_execution;
  constexpr struct caller_parallel_execution_t {} caller_parallel_execution;
  constexpr struct caller_concurrent_execution_t {} caller_concurrent_execution;

  // Properties for bulk execution guarantees:

  constexpr struct bulk_sequenced_execution_t {} bulk_sequenced_execution;
  constexpr struct bulk_parallel_execution_t {} bulk_parallel_execution;
  constexpr struct bulk_unsequenced_execution_t {} bulk_unsequenced_execution;

  // Properties for mapping of execution on to threads:

  constexpr struct other_execution_mapping_t {} other_execution_mapping;
  constexpr struct thread_execution_mapping_t {} thread_execution_mapping;
  constexpr struct new_thread_execution_mapping_t {} new_thread_execution_mapping;

  // Memory allocation properties:

  struct default_allocator_t {} default_allocator;
  template&lt;class ProtoAllocator&gt; struct allocator_wrapper_t { ProtoAllocator alloc; };
  struct allocator_t { template&lt;class ProtoAllocator&gt; constexpr allocator_wrapper_t&lt;ProtoAllocator&gt; operator()(const ProtoAllocator&amp; a) { return {a}; } } allocator;

  // Executor type traits:

  template&lt;class Executor&gt; struct is_executor;
  template&lt;class Executor&gt; struct is_oneway_executor;
  template&lt;class Executor&gt; struct is_twoway_executor;
  template&lt;class Executor&gt; struct is_then_executor;
  template&lt;class Executor&gt; struct is_bulk_oneway_executor;
  template&lt;class Executor&gt; struct is_bulk_twoway_executor;
  template&lt;class Executor&gt; struct is_bulk_then_executor;

  template&lt;class Executor&gt; constexpr bool is_executor_v = is_executor&lt;Executor&gt;::value;
  template&lt;class Executor&gt; constexpr bool is_oneway_executor_v = is_oneway_executor&lt;Executor&gt;::value;
  template&lt;class Executor&gt; constexpr bool is_twoway_executor_v = is_twoway_executor&lt;Executor&gt;::value;
  template&lt;class Executor&gt; constexpr bool is_then_executor_v = is_then_executor&lt;Executor&gt;::value;
  template&lt;class Executor&gt; constexpr bool is_bulk_oneway_executor_v = is_bulk_oneway_executor&lt;Executor&gt;::value;
  template&lt;class Executor&gt; constexpr bool is_bulk_twoway_executor_v = is_bulk_twoway_executor&lt;Executor&gt;::value;
  template&lt;class Executor&gt; constexpr bool is_bulk_then_executor_v = is_bulk_then_executor&lt;Executor&gt;::value;

  template&lt;class Executor&gt; struct executor_context;
  template&lt;class Executor, class T&gt; struct executor_future;
  template&lt;class Executor&gt; struct executor_shape;
  template&lt;class Executor&gt; struct executor_index;

  template&lt;class Executor&gt; using executor_context_t = typename executor_context&lt;Executor&gt;::type;
  template&lt;class Executor, class T&gt; using executor_future_t = typename executor_future&lt;Executor, T&gt;::type;
  template&lt;class Executor&gt; using executor_shape_t = typename executor_shape&lt;Executor&gt;::type;
  template&lt;class Executor&gt; using executor_index_t = typename executor_index&lt;Executor&gt;::type;

  // Member detection type traits for properties:

  template&lt;class Executor, class Property&gt; struct has_require_member;
  template&lt;class Executor, class Property&gt; struct has_query_member;

  template&lt;class Executor, class Property&gt;
    constexpr bool has_require_member_v = has_require_member&lt;Executor, Property&gt;::value;
  template&lt;class Executor, class Property&gt;
    constexpr bool has_query_member_v = has_query_member&lt;Executor, Property&gt;::value;

  // Member return type traits for properties:

  template&lt;class Executor, class Property&gt; struct require_member_result;
  template&lt;class Executor, class Property&gt; struct query_member_result;

  template&lt;class Executor, class Property&gt;
    using require_member_result_t = typename require_member_result&lt;Executor, Property&gt;::type;
  template&lt;class Executor, class Property&gt;
    using query_member_result_t = typename query_member_result&lt;Executor, Property&gt;::type;

  // Property value types traits:

  template&lt;class Executor, class Property&gt; struct property_value;

  template&lt;class Executor, class Property&gt;
    using property_value_t = typename property_value&lt;Executor, Property&gt;::type;

  // Customization points:

  namespace {
    constexpr unspecified require = unspecified;
    constexpr unspecified prefer = unspecified;
    constexpr unspecified query = unspecified;
  }

  // Customization point type traits:

  template&lt;class Executor, class... Properties&gt; struct can_require;
  template&lt;class Executor, class... Properties&gt; struct can_prefer;
  template&lt;class Executor, class Property&gt; struct can_query;

  template&lt;class Executor, class... Properties&gt;
    constexpr bool can_require_v = can_require&lt;Executor, Properties...&gt;::value;
  template&lt;class Executor, class... Properties&gt;
    constexpr bool can_prefer_v = can_prefer&lt;Executor, Properties...&gt;::value;
  template&lt;class Executor, class Property&gt;
    constexpr bool can_query_v = can_query&lt;Executor, Property&gt;::value;

  // Polymorphic executor wrappers:

  class bad_executor;
  class executor;

} // namespace execution
} // inline namespace concurrency_v2
} // namespace experimental
} // namespace std</code></pre>
<h2 id="requirements"><span class="header-section-number">1.1</span> Requirements</h2>
<h3 id="customization-point-objects"><span class="header-section-number">1.1.1</span> Customization point objects</h3>
<p><em>(The following text has been adapted from the draft Ranges Technical Specification.)</em></p>
<p>A <em>customization point object</em> is a function object (C++ Std, [function.objects]) with a literal class type that interacts with user-defined types while enforcing semantic requirements on that interaction.</p>
<p>The type of a customization point object shall satisfy the requirements of <code>CopyConstructible</code> (C++Std [copyconstructible]) and <code>Destructible</code> (C++Std [destructible]).</p>
<p>All instances of a specific customization point object type shall be equal.</p>
<p>Let <code>t</code> be a (possibly const) customization point object of type <code>T</code>, and <code>args...</code> be a parameter pack expansion of some parameter pack <code>Args...</code>. The customization point object <code>t</code> shall be callable as <code>t(args...)</code> when the types of <code>Args...</code> meet the requirements specified in that customization point object's definition. Otherwise, <code>T</code> shall not have a function call operator that participates in overload resolution.</p>
<p>Each customization point object type constrains its return type to satisfy some particular type requirements.</p>
<p>The library defines several named customization point objects. In every translation unit where such a name is defined, it shall refer to the same instance of the customization point object.</p>
<p>[<em>Note:</em> Many of the customization points objects in the library evaluate function call expressions with an unqualified name which results in a call to a user-defined function found by argument dependent name lookup (C++Std [basic.lookup.argdep]). To preclude such an expression resulting in a call to unconstrained functions with the same name in namespace <code>std</code>, customization point objects specify that lookup for these expressions is performed in a context that includes deleted overloads matching the signatures of overloads defined in namespace <code>std</code>. When the deleted overloads are viable, user-defined overloads must be more specialized (C++Std [temp.func.order]) to be used by a customization point object. <em>--end note</em>]</p>
<h3 id="future-requirements"><span class="header-section-number">1.1.2</span> <code>Future</code> requirements</h3>
<p>A type <code>F</code> meets the <code>Future</code> requirements for some value type <code>T</code> if <code>F</code> is <code>std::experimental::future&lt;T&gt;</code> (defined in the C++ Concurrency TS, ISO/IEC TS 19571:2016). [<em>Note:</em> This concept is included as a placeholder to be elaborated, with the expectation that the elaborated requirements for <code>Future</code> will expand the applicability of some executor customization points. <em>--end note</em>]</p>
<h3 id="protoallocator-requirements"><span class="header-section-number">1.1.3</span> <code>ProtoAllocator</code> requirements</h3>
<p>A type <code>A</code> meets the <code>ProtoAllocator</code> requirements if <code>A</code> is <code>CopyConstructible</code> (C++Std [copyconstructible]), <code>Destructible</code> (C++Std [destructible]), and <code>allocator_traits&lt;A&gt;::rebind_alloc&lt;U&gt;</code> meets the allocator requirements (C++Std [allocator.requirements]), where <code>U</code> is an object type. [<em>Note:</em> For example, <code>std::allocator&lt;void&gt;</code> meets the proto-allocator requirements but not the allocator requirements. <em>--end note</em>] No comparison operator, copy operation, move operation, or swap operation on these types shall exit via an exception.</p>
<h3 id="executioncontext-requirements"><span class="header-section-number">1.1.4</span> <code>ExecutionContext</code> requirements</h3>
<p>A type meets the <code>ExecutionContext</code> requirements if it satisfies the <code>EqualityComparable</code> requirements (C++Std [equalitycomparable]). No comparison operator on these types shall exit via an exception.</p>
<h3 id="baseexecutor-requirements"><span class="header-section-number">1.1.5</span> <code>BaseExecutor</code> requirements</h3>
<p>A type <code>X</code> meets the <code>BaseExecutor</code> requirements if it satisfies the requirements of <code>CopyConstructible</code> (C++Std [copyconstructible]), <code>Destructible</code> (C++Std [destructible]), and <code>EqualityComparable</code> (C++Std [equalitycomparable]), as well as the additional requirements listed below.</p>
<p>No comparison operator, copy operation, move operation, swap operation, or member function <code>context</code> on these types shall exit via an exception.</p>
<p>The executor copy constructor, comparison operators, <code>context</code> member function, associated execution functions, and other member functions defined in refinements (TODO: what should this word be?) of the <code>BaseExecutor</code> requirements shall not introduce data races as a result of concurrent calls to those functions from different threads.</p>
<p>The destructor shall not block pending completion of the submitted function objects. [<em>Note:</em> The ability to wait for completion of submitted function objects may be provided by the associated execution context. <em>--end note</em>]</p>
<p>In the Table  below, <code>x1</code> and <code>x2</code> denote (possibly const) values of type <code>X</code>, <code>mx1</code> denotes an xvalue of type <code>X</code>, and <code>u</code> denotes an identifier.</p>
<table style="width:90%;">
<caption>(Base executor requirements) </caption>
<colgroup>
<col width="20%" />
<col width="18%" />
<col width="51%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Expression</th>
<th align="left">Type</th>
<th align="left">Assertion/note/pre-/post-condition</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>X u(x1);</code></td>
<td align="left"></td>
<td align="left">Shall not exit via an exception. <br/><br/><em>Post:</em> <code>u == x1</code> and <code>u.context() == x1.context()</code>.</td>
</tr>
<tr class="even">
<td align="left"><code>X u(mx1);</code></td>
<td align="left"></td>
<td align="left">Shall not exit via an exception. <br/><br/><em>Post:</em> <code>u</code> equals the prior value of <code>mx1</code> and <code>u.context()</code> equals the prior value of <code>mx1.context()</code>.</td>
</tr>
<tr class="odd">
<td align="left"><code>x1 == x2</code></td>
<td align="left"><code>bool</code></td>
<td align="left">Returns <code>true</code> only if <code>x1</code> and <code>x2</code> can be interchanged with identical effects in any of the expressions defined in these type requirements (TODO and the other executor requirements defined in this Technical Specification). [<em>Note:</em> Returning <code>false</code> does not necessarily imply that the effects are not identical. <em>--end note</em>] <code>operator==</code> shall be reflexive, symmetric, and transitive, and shall not exit via an exception.</td>
</tr>
<tr class="even">
<td align="left"><code>x1 != x2</code></td>
<td align="left"><code>bool</code></td>
<td align="left">Same as <code>!(x1 == x2)</code>.</td>
</tr>
<tr class="odd">
<td align="left"><code>x1.context()</code></td>
<td align="left"><code>E&amp;</code> or <code>const E&amp;</code> where <code>E</code> is a type that satisfies the <code>ExecutionContext</code> requirements.</td>
<td align="left">Shall not exit via an exception. The comparison operators and member functions defined in these requirements (TODO and the other executor requirements defined in this Technical Specification) shall not alter the reference returned by this function.</td>
</tr>
</tbody>
</table>
<p>[<em>Commentary: The equality operator is specified primarily as an aid to support postconditons on executor copy construction and move construction. The key word in supporting these postconditions is &quot;interchanged&quot;. That is, if a copy is substituted for the original executor it shall produce identical effects, provided the expression, calling context, and program state are otherwise identical. Calls to the copied executor from a different context or program state are not required to produce identical effects, and this is not considered an &quot;interchanged&quot; use of an executor. In particular, even consecutive calls to the same executor need not produce identical effects since the program state has already altered.</em>]</p>
<h3 id="onewayexecutor-requirements"><span class="header-section-number">1.1.6</span> <code>OneWayExecutor</code> requirements</h3>
<p>The <code>OneWayExecutor</code> requirements specify requirements for executors which create execution agents without a channel for awaiting the completion of a submitted function object and obtaining its result. [<em>Note:</em> That is, the executor provides fire-and-forget semantics. <em>--end note</em>]</p>
<p>A type <code>X</code> satisfies the <code>OneWayExecutor</code> requirements if it satisfies the <code>BaseExecutor</code> requirements, as well as the requirements in the table below.</p>
<p>In the Table below, <code>x</code> denotes a (possibly const) executor object of type <code>X</code> and <code>f</code> denotes a function object of type <code>F&amp;&amp;</code> callable as <code>DECAY_COPY(std::forward&lt;F&gt;(f))()</code> and where <code>decay_t&lt;F&gt;</code> satisfies the <code>MoveConstructible</code> requirements.</p>
<table style="width:69%;">
<colgroup>
<col width="18%" />
<col width="19%" />
<col width="31%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Expression</th>
<th align="left">Return Type</th>
<th align="left">Operational semantics</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>x.execute(f)</code></td>
<td align="left"><code>void</code></td>
<td align="left">Creates an execution agent which invokes <code>DECAY_COPY( std::forward&lt;F&gt;(f))()</code> at most once, with the call to <code>DECAY_COPY</code> being evaluated in the thread that called <code>execute</code>. <br/> <br/> May block forward progress of the caller until <code>DECAY_COPY( std::forward&lt;F&gt;(f))()</code> finishes execution. <br/> <br/> The invocation of <code>execute</code> synchronizes with (C++Std [intro.multithread]) the invocation of <code>f</code>. <br/> <br/> <code>execute</code> shall not propagate any exception thrown by <code>DECAY_COPY( std::forward&lt;F&gt;(f))()</code> or any other function submitted to the executor. [<em>Note:</em> The treatment of exceptions thrown by one-way submitted functions is specific to the concrete executor type. <em>--end note.</em>]</td>
</tr>
</tbody>
</table>
<h3 id="twowayexecutor-requirements"><span class="header-section-number">1.1.7</span> <code>TwoWayExecutor</code> requirements</h3>
<p>The <code>TwoWayExecutor</code> requirements specify requirements for executors which creating execution agents with a channel for awaiting the completion of a submitted function object and obtaining its result.</p>
<p>A type <code>X</code> satisfies the <code>TwoWayExecutor</code> requirements if it satisfies the <code>BaseExecutor</code> requirements, as well as the requirements in the table below.</p>
<p>In the Table below, <code>x</code> denotes a (possibly const) executor object of type <code>X</code>, <code>f</code> denotes a function object of type <code>F&amp;&amp;</code> callable as <code>DECAY_COPY(std::forward&lt;F&gt;(f))()</code> and where <code>decay_t&lt;F&gt;</code> satisfies the <code>MoveConstructible</code> requirements, and <code>R</code> denotes the type of the expression <code>DECAY_COPY(std::forward&lt;F&gt;(f))()</code>.</p>
<table style="width:69%;">
<colgroup>
<col width="18%" />
<col width="19%" />
<col width="31%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Expression</th>
<th align="left">Return Type</th>
<th align="left">Operational semantics</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>x.twoway_execute(f)</code></td>
<td align="left">A type that satisfies the <code>Future</code> requirements for the value type <code>R</code>.</td>
<td align="left">Creates an execution agent which invokes <code>DECAY_COPY( std::forward&lt;F&gt;(f))()</code> at most once, with the call to <code>DECAY_COPY</code> being evaluated in the thread that called <code>twoway_execute</code>. <br/> <br/> May block forward progress of the caller until <code>DECAY_COPY( std::forward&lt;F&gt;(f))()</code> finishes execution. <br/> <br/> The invocation of <code>twoway_execute</code> synchronizes with (C++Std [intro.multithread]) the invocation of <code>f</code>. <br/> <br/> Stores the result of <code>DECAY_COPY( std::forward&lt;F&gt;(f))()</code>, or any exception thrown by <code>DECAY_COPY( std::forward&lt;F&gt;(f))()</code>, in the associated shared state of the resulting <code>Future</code>.</td>
</tr>
</tbody>
</table>
<h3 id="thenexecutor-requirements"><span class="header-section-number">1.1.8</span> <code>ThenExecutor</code> requirements</h3>
<p>The <code>ThenExecutor</code> requirements specify requirements for executors which create execution agents whose initiation is predicated on the readiness of a specified future, and which provide a channel for awaiting the completion of the submitted function object and obtaining its result.</p>
<p>A type <code>X</code> satisfies the <code>ThenExecutor</code> requirements if it satisfies the <code>BaseExecutor</code> requirements, as well as the requirements in the table below.</p>
<p>In the Table below, <code>x</code> denotes a (possibly const) executor object of type <code>X</code>, <code>fut</code> denotes a future object satisfying the Future requirements, <code>f</code> denotes a function object of type <code>F&amp;&amp;</code> callable as <code>DECAY_COPY(std::forward&lt;F&gt;(f))(fut)</code> and where <code>decay_t&lt;F&gt;</code> satisfies the <code>MoveConstructible</code> requirements, and <code>R</code> denotes the type of the expression <code>DECAY_COPY(std::forward&lt;F&gt;(f))(fut)</code>.</p>
<table style="width:69%;">
<colgroup>
<col width="18%" />
<col width="19%" />
<col width="31%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Expression</th>
<th align="left">Return Type</th>
<th align="left">Operational semantics</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>x.then_execute(f, fut)</code></td>
<td align="left">A type that satisfies the <code>Future</code> requirements for the value type <code>R</code>.</td>
<td align="left">When <code>fut</code> is ready, creates an execution agent which invokes <code>DECAY_COPY( std::forward&lt;F&gt;(f))(fut)</code> at most once, with the call to <code>DECAY_COPY</code> being evaluated in the thread that called <code>then_execute</code>. <br/> <br/> May block forward progress of the caller until <code>DECAY_COPY( std::forward&lt;F&gt;(f))(fut)</code> finishes execution. <br/> <br/> The invocation of <code>then_execute</code> synchronizes with (C++Std [intro.multithread]) the invocation of <code>f</code>. <br/> <br/> Stores the result of <code>DECAY_COPY( std::forward&lt;F&gt;(f))(fut)</code>, or any exception thrown by <code>DECAY_COPY( std::forward&lt;F&gt;(f))(fut)</code>, in the associated shared state of the resulting <code>Future</code>.</td>
</tr>
</tbody>
</table>
<h3 id="bulkonewayexecutor-requirements"><span class="header-section-number">1.1.9</span> <code>BulkOneWayExecutor</code> requirements</h3>
<p>The <code>BulkOneWayExecutor</code> requirements specify requirements for executors which create groups of execution agents in bulk from a single execution function, without a channel for awaiting the completion of the submitted function object invocations and obtaining their result. [<em>Note:</em> That is, the executor provides fire-and-forget semantics. <em>--end note</em>]</p>
<p>A type <code>X</code> satisfies the <code>BulkOneWayExecutor</code> requirements if it satisfies the <code>BaseExecutor</code> requirements, as well as the requirements in the table below.</p>
<p>In the Table below,</p>
<ul>
<li><code>x</code> denotes a (possibly const) executor object of type <code>X</code>,</li>
<li><code>n</code> denotes a shape object whose type is <code>executor_shape_t&lt;X&gt;</code>,</li>
<li><code>sf</code> denotes a <code>CopyConstructible</code> function object with zero arguments whose result type is <code>S</code>,</li>
<li><code>i</code> denotes a (possibly const) object whose type is <code>executor_index_t&lt;X&gt;</code>,</li>
<li><code>s</code> denotes an object whose type is <code>S</code>,</li>
<li><code>f</code> denotes a function object of type <code>F&amp;&amp;</code> callable as <code>DECAY_COPY(std::forward&lt;F&gt;(f))(i, s)</code> and where <code>decay_t&lt;F&gt;</code> satisfies the <code>MoveConstructible</code> requirements.</li>
</ul>
<table style="width:69%;">
<colgroup>
<col width="18%" />
<col width="19%" />
<col width="31%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Expression</th>
<th align="left">Return Type</th>
<th align="left">Operational semantics</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>x.bulk_execute(f, n, sf)</code></td>
<td align="left"><code>void</code></td>
<td align="left">Invokes <code>sf()</code> on an unspecified execution agent to produce the value <code>s</code>. Creates a group of execution agents of shape <code>n</code> which invokes <code>DECAY_COPY( std::forward&lt;F&gt;(f))(i, s)</code> at most once for each value of <code>i</code> in the range <code>[0,n)</code>, with the call to <code>DECAY_COPY</code> being evaluated in the thread that called <code>bulk_execute</code>. <br/> <br/> May block forward progress of the caller until one or more calls to <code>DECAY_COPY( std::forward&lt;F&gt;(f))(i, s)</code> finish execution. <br/> <br/> The invocation of <code>bulk_execute</code> synchronizes with (C++Std [intro.multithread]) the invocations of <code>f</code>. <br/> <br/> <code>bulk_execute</code> shall not propagate any exception thrown by <code>DECAY_COPY( std::forward&lt;F&gt;(f))(i, s)</code> or any other function submitted to the executor. [<em>Note:</em> The treatment of exceptions thrown by bulk one-way submitted functions is specific to the concrete executor type. <em>--end note.</em>]</td>
</tr>
</tbody>
</table>
<h3 id="bulktwowayexecutor-requirements"><span class="header-section-number">1.1.10</span> <code>BulkTwoWayExecutor</code> requirements</h3>
<p>The <code>BulkTwoWayExecutor</code> requirements specify requirements for executors which create groups of execution agents in bulk from a single execution function with a channel for awaiting the completion of a submitted function object invoked by those execution agents and obtaining its result.</p>
<p>A type <code>X</code> satisfies the <code>BulkTwoWayExecutor</code> requirements if it satisfies the <code>BaseExecutor</code> requirements, as well as the requirements in the table below.</p>
<p>In the Table below,</p>
<ul>
<li><code>x</code> denotes a (possibly const) executor object of type <code>X</code>,</li>
<li><code>n</code> denotes a shape object whose type is <code>executor_shape_t&lt;X&gt;</code>,</li>
<li><code>rf</code> denotes a <code>CopyConstructible</code> function object with zero arguments whose result type is <code>R</code>,</li>
<li><code>sf</code> denotes a <code>CopyConstructible</code> function object with zero arguments whose result type is <code>S</code>,</li>
<li><code>i</code> denotes a (possibly const) object whose type is <code>executor_index_t&lt;X&gt;</code>,</li>
<li><code>s</code> denotes an object whose type is <code>S</code>,</li>
<li>if <code>R</code> is non-void,
<ul>
<li><code>r</code> denotes an object whose type is <code>R</code>,</li>
<li><code>f</code> denotes a function object of type <code>F&amp;&amp;</code> callable as <code>DECAY_COPY(std::forward&lt;F&gt;(f))(i, r, s)</code> and where <code>decay_t&lt;F&gt;</code> satisfies the <code>MoveConstructible</code> requirements.</li>
</ul></li>
<li>if <code>R</code> is void,
<ul>
<li><code>f</code> denotes a function object of type <code>F&amp;&amp;</code> callable as <code>DECAY_COPY(std::forward&lt;F&gt;(f))(i, s)</code> and where <code>decay_t&lt;F&gt;</code> satisfies the <code>MoveConstructible</code> requirements.</li>
</ul></li>
</ul>
<table style="width:69%;">
<colgroup>
<col width="18%" />
<col width="19%" />
<col width="31%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Expression</th>
<th align="left">Return Type</th>
<th align="left">Operational semantics</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>x.bulk_twoway_execute(f, n, rf, sf)</code></td>
<td align="left">A type that satisfies the <code>Future</code> requirements for the value type <code>R</code>.</td>
<td align="left">If <code>R</code> is non-void, invokes <code>rf()</code> on an unspecified execution agent to produce the value <code>r</code>. Invokes <code>sf()</code> on an unspecified execution agent to produce the value <code>s</code>. Creates a group of execution agents of shape <code>n</code> which invokes <code>DECAY_COPY( std::forward&lt;F&gt;(f))(i, r, s)</code> if <code>R</code> is non-void, and otherwise invokes <code>DECAY_COPY( std::forward&lt;F&gt;(f))(i, s)</code>, at most once for each value of <code>i</code> in the range <code>[0,n)</code>, with the call to <code>DECAY_COPY</code> being evaluated in the thread that called <code>bulk_twoway_execute</code>. <br/> <br/> May block forward progress of the caller until one or more invocations of <code>f</code> finish execution. <br/> <br/> The invocation of <code>bulk_twoway_execute</code> synchronizes with (C++Std [intro.multithread]) the invocations of <code>f</code>. <br/> <br/> Once all invocations of <code>f</code> finish execution, stores <code>r</code>, or any exception thrown by an invocation of <code>f</code>, in the associated shared state of the resulting <code>Future</code>.</td>
</tr>
</tbody>
</table>
<h3 id="bulkthenexecutor-requirements"><span class="header-section-number">1.1.11</span> <code>BulkThenExecutor</code> requirements</h3>
<p>The <code>BulkThenExecutor</code> requirements specify requirements for executors which create execution agents whose initiation is predicated on the readiness of a specified future, and which provide a channel for awaiting the completion of the submitted function object and obtaining its result.</p>
<p>A type <code>X</code> satisfies the <code>BulkThenExecutor</code> requirements if it satisfies the <code>BaseExecutor</code> requirements, as well as the requirements in the table below.</p>
<p>In the Table below,</p>
<ul>
<li><code>x</code> denotes a (possibly const) executor object of type <code>X</code>,</li>
<li><code>n</code> denotes a shape object whose type is <code>executor_shape_t&lt;X&gt;</code>,</li>
<li><code>fut</code> denotes a future object satisfying the Future requirements,</li>
<li><code>rf</code> denotes a <code>CopyConstructible</code> function object with zero arguments whose result type is <code>R</code>,</li>
<li><code>sf</code> denotes a <code>CopyConstructible</code> function object with zero arguments whose result type is <code>S</code>,</li>
<li><code>i</code> denotes a (possibly const) object whose type is <code>executor_index_t&lt;X&gt;</code>,</li>
<li><code>s</code> denotes an object whose type is <code>S</code>,</li>
<li>if <code>R</code> is non-void,
<ul>
<li><code>r</code> denotes an object whose type is <code>R</code>,</li>
<li><code>f</code> denotes a function object of type <code>F&amp;&amp;</code> callable as <code>DECAY_COPY(std::forward&lt;F&gt;(f))(i, fut, r, s)</code> and where <code>decay_t&lt;F&gt;</code> satisfies the <code>MoveConstructible</code> requirements.</li>
</ul></li>
<li>if <code>R</code> is void,
<ul>
<li><code>f</code> denotes a function object of type <code>F&amp;&amp;</code> callable as <code>DECAY_COPY(std::forward&lt;F&gt;(f))(i, fut, s)</code> and where <code>decay_t&lt;F&gt;</code> satisfies the <code>MoveConstructible</code> requirements.</li>
</ul></li>
</ul>
<table style="width:69%;">
<colgroup>
<col width="18%" />
<col width="19%" />
<col width="31%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Expression</th>
<th align="left">Return Type</th>
<th align="left">Operational semantics</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>x.bulk_then_execute(f, n, fut, rf, sf)</code></td>
<td align="left">A type that satisfies the <code>Future</code> requirements for the value type <code>R</code>.</td>
<td align="left">If <code>R</code> is non-void, invokes <code>rf()</code> on an unspecified execution agent to produce the value <code>r</code>. Invokes <code>sf()</code> on an unspecified execution agent to produce the value <code>s</code>. When <code>fut</code> is ready, creates a group of execution agents of shape <code>n</code> which invokes <code>DECAY_COPY( std::forward&lt;F&gt;(f))(i, fut, r, s)</code> if <code>R</code> is non-void, and otherwise invokes <code>DECAY_COPY( std::forward&lt;F&gt;(f))(i, fut, s)</code>, at most once for each value of <code>i</code> in the range <code>[0,n)</code>, with the call to <code>DECAY_COPY</code> being evaluated in the thread that called <code>bulk_then_execute</code>. <br/> <br/> May block forward progress of the caller until one or more invocations of <code>f</code> finish execution. <br/> <br/> The invocation of <code>bulk_then_execute</code> synchronizes with (C++Std [intro.multithread]) the invocations of <code>f</code>. <br/> <br/> Once all invocations of <code>f</code> finish execution, stores <code>r</code>, or any exception thrown by an invocation of <code>f</code>, in the associated shared state of the resulting <code>Future</code>.</td>
</tr>
</tbody>
</table>
<h2 id="executor-properties"><span class="header-section-number">1.2</span> Executor properties</h2>
<h3 id="in-general"><span class="header-section-number">1.2.1</span> In general</h3>
<p>An executor's behavior in generic contexts is determined by a set of executor properties, and each executor property imposes certain requirements on the executor.</p>
<p>Given an existing executor, a related executor with different properties may be created by calling the <code>require</code> member or non-member functions. These functions behave according the table below. In the table below, <code>x</code> denotes a (possibly const) executor object of type <code>X</code>, and <code>p</code> denotes a (possibly const) property object.</p>
<p>[<em>Note:</em> As a general design note properties which define a mutually exclusive pair, that describe an enabled or non-enabled behaviour follow the convention of having the same property name for both with the <code>not_</code> prefix to the property for the non-enabled behaviour. <em>--end note</em>]</p>
<table style="width:33%;">
<colgroup>
<col width="18%" />
<col width="15%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Expression</th>
<th align="left">Comments</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>x.require(p)</code> <br/> <code>require(x,p)</code></td>
<td align="left">Returns an executor object with the requested property <code>p</code> added to the set. All other properties of the returned executor are identical to those of <code>x</code>, except where those properties are described below as being mutually exclusive to <code>p</code>. In this case, the mutually exclusive properties are implicitly removed from the set associated with the returned executor. <br/> <br/> The expression is ill formed if an executor is unable to add the requested property.</td>
</tr>
</tbody>
</table>
<p>The current value of an executor's properties can be queried by calling the <code>query</code> function. This function behaves according the table below. In the table below, <code>x</code> denotes a (possibly const) executor object of type <code>X</code>, and <code>p</code> denotes a (possibly const) property object.</p>
<table style="width:33%;">
<colgroup>
<col width="18%" />
<col width="15%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Expression</th>
<th align="left">Comments</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>x.query(p)</code></td>
<td align="left">Returns the current value of the requested property <code>p</code>. The expression is ill formed if an executor is unable to return the requested property.</td>
</tr>
</tbody>
</table>
<h3 id="directionality-properties"><span class="header-section-number">1.2.2</span> Directionality properties</h3>
<pre><code>constexpr struct oneway_t {} oneway;
constexpr struct twoway_t {} twoway;
constexpr struct then_t {} then;</code></pre>
<table style="width:36%;">
<colgroup>
<col width="15%" />
<col width="20%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Property</th>
<th align="left">Requirements</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>oneway</code></td>
<td align="left">The executor type satisfies the <code>OneWayExecutor</code> or <code>BulkOneWayExecutor</code> requirements.</td>
</tr>
<tr class="even">
<td align="left"><code>twoway</code></td>
<td align="left">The executor type satisfies the <code>TwoWayExecutor</code> or <code>BulkTwoWayExecutor</code> requirements.</td>
</tr>
<tr class="odd">
<td align="left"><code>then</code></td>
<td align="left">The executor type satisfies the <code>ThenExecutor</code> or <code>BulkThenExecutor</code> requirements.</td>
</tr>
</tbody>
</table>
<p>The <code>oneway</code>, <code>twoway</code> and <code>then</code> properties are not mutually exclusive.</p>
<h3 id="cardinality-properties"><span class="header-section-number">1.2.3</span> Cardinality properties</h3>
<pre><code>constexpr struct single_t {} single;
constexpr struct bulk_t {} bulk;</code></pre>
<table style="width:36%;">
<colgroup>
<col width="15%" />
<col width="20%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Property</th>
<th align="left">Requirements</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>single</code></td>
<td align="left">The executor type satisfies the <code>OneWayExecutor</code>, <code>TwoWayExecutor</code>, or <code>ThenExecutor</code> requirements.</td>
</tr>
<tr class="even">
<td align="left"><code>bulk</code></td>
<td align="left">The executor type satisfies the <code>BulkOneWayExecutor</code>, <code>BulkTwoWayExecutor</code>, or <code>BulkThenExecutor</code> requirements.</td>
</tr>
</tbody>
</table>
<p>The <code>single</code> and <code>bulk</code> properties are not mutually exclusive.</p>
<h3 id="blocking-properties"><span class="header-section-number">1.2.4</span> Blocking properties</h3>
<pre><code>constexpr struct possibly_blocking_t {} possibly_blocking;
constexpr struct always_blocking_t {} always_blocking;
constexpr struct never_blocking_t {} never_blocking;</code></pre>
<table style="width:36%;">
<colgroup>
<col width="15%" />
<col width="20%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Property</th>
<th align="left">Requirements</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>possibly_blocking</code></td>
<td align="left">A call to an executor's execution function may block pending completion of one or more of the execution agents created by that execution function.</td>
</tr>
<tr class="even">
<td align="left"><code>always_blocking</code></td>
<td align="left">A call to an executor's execution function shall block until completion of all execution agents created by that execution function.</td>
</tr>
<tr class="odd">
<td align="left"><code>never_blocking</code></td>
<td align="left">A call to an executor's execution function shall not block pending completion of the execution agents created by that execution function.</td>
</tr>
</tbody>
</table>
<p>The <code>possibly_blocking</code>, <code>always_blocking</code> and <code>never_blocking</code> properties are mutually exclusive.</p>
<p>[<em>Note:</em> The guarantees of <code>possibly_blocking</code>, <code>always_blocking</code> and <code>never_blocking</code> implies the relationships: <code>possibly_blocking &lt; always_blocking</code> and <code>possibly_blocking &lt; never_blocking</code> <em>--end note</em>]</p>
<h4 id="properties-to-indicate-if-blocking-and-directionality-may-be-adapted"><span class="header-section-number">1.2.4.1</span> Properties to indicate if blocking and directionality may be adapted</h4>
<pre><code>constexpr struct adaptable_blocking_t {} adaptable_blocking;
constexpr struct not_adaptable_blocking_t {} not_adaptable_blocking;</code></pre>
<table style="width:36%;">
<colgroup>
<col width="15%" />
<col width="20%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Property</th>
<th align="left">Requirements</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>adaptable_blocking</code></td>
<td align="left">The <code>require</code> customization point may adapt the executor to add the <code>two_way</code> or <code>always_blocking</code> properties.</td>
</tr>
<tr class="even">
<td align="left"><code>not_adaptable_blocking</code></td>
<td align="left">The <code>require</code> customization point may not adapt the executor to add the <code>two_way</code> or <code>always_blocking</code> properties.</td>
</tr>
</tbody>
</table>
<p>The <code>not_adaptable_blocking</code> and <code>adaptable_blocking</code> properties are mutually exclusive.</p>
<p>[<em>Note:</em> The <code>two_way</code> property is included here as the <code>require</code> customization point's <code>two_way</code> adaptation is specified in terms of <code>std::experimental::future</code>, and that template supports blocking wait operations. <em>--end note</em>]</p>
<h4 id="properties-to-indicate-if-submitted-tasks-represent-continuations"><span class="header-section-number">1.2.4.2</span> Properties to indicate if submitted tasks represent continuations</h4>
<pre><code>constexpr struct continuation_t {} continuation;
constexpr struct not_continuation_t {} not_continuation;</code></pre>
<table style="width:36%;">
<colgroup>
<col width="15%" />
<col width="20%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Property</th>
<th align="left">Requirements</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>continuation</code></td>
<td align="left">Function objects submitted through the executor represent continuations of the caller. If the caller is a lightweight execution agent managed by the executor or its associated execution context, the execution of the submitted function object may be deferred until the caller completes.</td>
</tr>
<tr class="even">
<td align="left"><code>not_continuation</code></td>
<td align="left">Function objects submitted through the executor do not represent continuations of the caller.</td>
</tr>
</tbody>
</table>
<p>The <code>not_continuation</code> and <code>continuation</code> properties are mutually exclusive.</p>
<h3 id="properties-to-indicate-likely-task-submission-in-the-future"><span class="header-section-number">1.2.5</span> Properties to indicate likely task submission in the future</h3>
<pre><code>constexpr struct not_outstanding_work_t {} not_outstanding_work;
constexpr struct outstanding_work_t {} outstanding_work;</code></pre>
<table style="width:36%;">
<colgroup>
<col width="15%" />
<col width="20%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Property</th>
<th align="left">Requirements</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>outstanding_work</code></td>
<td align="left">The existence of the executor object represents an indication of likely future submission of a function object. The executor or its associated execution context may choose to maintain execution resources in anticipation of this submission.</td>
</tr>
<tr class="even">
<td align="left"><code>not_outstanding_work</code></td>
<td align="left">The existence of the executor object does not indicate any likely future submission of a function object.</td>
</tr>
</tbody>
</table>
<p>The <code>not_outstanding_work</code> and <code>outstanding_work</code> properties are mutually exclusive.</p>
<p>[<em>Note:</em> The <code>outstanding_work</code> and <code>not_outstanding_work</code> properties are use to communicate to the associated execution context intended future work submission on the executor. The intended effect of the properties is the behavior of execution context's facilities for awaiting outstanding work; specifically whether it considers the existance of the executor object with the <code>outstanding_work</code> property enabled outstanding work when deciding what to wait on. However this will be largely defined by the execution context implementation. It is intended that the execution context will define its wait facilities and on-destruction behaviour and provide an interface for querying this. An initial work towards this is included in P0737r0. <em>--end note</em>]</p>
<h3 id="properties-for-execution-forward-progress-guarantees-with-caller"><span class="header-section-number">1.2.6</span> Properties for execution forward progress guarantees with caller</h3>
<p>These properties communicate the forward progress and ordering guarantees of execution agent(s) with respect to the caller.</p>
<pre><code>constexpr struct caller_weakly_parallel_execution_t {} caller_weakly_parallel_execution;
constexpr struct caller_parallel_execution_t {} caller_parallel_execution;
constexpr struct caller_concurrent_execution_t {} caller_concurrent_execution;</code></pre>
<table style="width:36%;">
<colgroup>
<col width="15%" />
<col width="20%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Property</th>
<th align="left">Requirements</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>caller_weakly_parallel_execution</code></td>
<td align="left">Each execution agent must provide weakly <em>parallel forward progress</em> guarantees with respect to the calling thread.</td>
</tr>
<tr class="even">
<td align="left"><code>caller_parallel_execution</code></td>
<td align="left">Each execution agent must provide <em>parallel forward progress</em> guarantees with respect to the calling thread.</td>
</tr>
<tr class="odd">
<td align="left"><code>caller_concurrent_execution</code></td>
<td align="left">Each execution agent must provide <em>concurrent forward progress</em> guarantees with respect to the calling thread.</td>
</tr>
</tbody>
</table>
<p>The <code>caller_weakly_parallel_execution</code>, <code>caller_parallel_execution</code>, and <code>caller_concurrent_execution</code> properties are mutually exclusive.</p>
<p>[<em>Note:</em> The guarantees of <code>caller_weakly_parallel_execution</code>, <code>caller_parallel_execution</code> and <code>caller_concurrent_execution</code> implies the relationship: <code>caller_weakly_parallel_execution &lt; caller_parallel_execution &lt; caller_concurrent_execution</code> <em>--end note</em>]</p>
<h3 id="properties-for-bulk-execution-guarantees"><span class="header-section-number">1.2.7</span> Properties for bulk execution guarantees</h3>
<p>These properties communicate the forward progress and ordering guarantees of execution agents with respect to other agents within the same bulk submission.</p>
<pre><code>constexpr struct bulk_sequenced_execution_t {} bulk_sequenced_execution;
constexpr struct bulk_parallel_execution_t {} bulk_parallel_execution;
constexpr struct bulk_unsequenced_execution_t {} bulk_unsequenced_execution;</code></pre>
<table style="width:36%;">
<colgroup>
<col width="15%" />
<col width="20%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Property</th>
<th align="left">Requirements</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>bulk_sequenced_execution</code></td>
<td align="left">Execution agents within the same bulk execution may not be parallelized.</td>
</tr>
<tr class="even">
<td align="left"><code>bulk_parallel_execution</code></td>
<td align="left">Execution agents within the same bulk execution may be parallelized.</td>
</tr>
<tr class="odd">
<td align="left"><code>bulk_unsequenced_execution</code></td>
<td align="left">Execution agents within the same bulk execution may be parallelized and vectorized.</td>
</tr>
</tbody>
</table>
<p>Execution agents created by executors with the <code>bulk_sequenced_execution</code> property execute in sequence in lexicographic order of their indices.</p>
<p>Execution agents created by executors with the <code>bulk_parallel_execution</code> property execute with a parallel forward progress guarantee. Any such agents executing in the same thread of execution are indeterminately sequenced with respect to each other. [<em>Note:</em> It is the caller's responsibility to ensure that the invocation does not introduce data races or deadlocks. <em>--end note</em>]</p>
<p>Execution agents created by executors with the <code>bulk_unsequenced_execution</code> property may execute in an unordered fashion. Any such agents executing in the same thread of execution are unsequenced with respect to each other. [<em>Note:</em> This means that multiple execution agents may be interleaved on a single thread of execution, which overrides the usual guarantee from [intro.execution] that function executions do not interleave with one another. <em>--end note</em>]</p>
<p>[<em>Editorial note:</em> The descriptions of these properties were ported from [algorithms.parallel.user]. The intention is that a future standard will specify execution policy behavior in terms of the fundamental properties of their associated executors. We did not include the accompanying code examples from [algorithms.parallel.user] because the examples seem easier to understand when illustrated by <code>std::for_each</code>. <em>--end editorial note</em>]</p>
<p>[<em>Note:</em> The guarantees provided by these properties implies the relationship: <code>bulk_unsequenced_execution &lt; bulk_parallel_execution &lt; bulk_sequenced_execution</code>. <em>--end note</em>]</p>
<p>[<em>Editorial note:</em> The note above is intended to describe when one bulk executor can be substituted for another and provide the required semantics. For example, if a user needs sequenced execution, then only an executor with the <code>bulk_sequenced_execution</code> property will do. On the other hand, if a user only needs <code>bulk_unsequenced_execution</code>, then an executor with any of the above properties will suffice. <em>--end editorial note</em>]</p>
<p>The <code>bulk_unsequenced_execution</code>, <code>bulk_parallel_execution</code>, and <code>bulk_sequenced_execution</code> properties are mutually exclusive.</p>
<h3 id="properties-for-mapping-of-execution-on-to-threads"><span class="header-section-number">1.2.8</span> Properties for mapping of execution on to threads</h3>
<pre><code>constexpr struct other_execution_mapping_t {} default_execution_mapping;
constexpr struct thread_execution_mapping_t {} thread_execution_mapping;
constexpr struct new_thread_execution_mapping_t {} new_thread_execution_mapping;</code></pre>
<table style="width:36%;">
<colgroup>
<col width="15%" />
<col width="20%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Property</th>
<th align="left">Requirements</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>other_execution_mapping</code></td>
<td align="left">Mapping of each execution agent created by the executor is implementation defined.</td>
</tr>
<tr class="even">
<td align="left"><code>thread_execution_mapping</code></td>
<td align="left">Execution agents created by the executor are mapped onto threads of execution.</td>
</tr>
<tr class="odd">
<td align="left"><code>new_thread_execution_mapping</code></td>
<td align="left">Each execution agent created by the executor is mapped onto a new thread of execution.</td>
</tr>
</tbody>
</table>
<p>The <code>other_execution_mapping</code>, <code>thread_execution_mapping</code> and <code>new_thread_execution_mapping</code> properties are mutually exclusive.</p>
<p>[<em>Note:</em> The guarantees of <code>other_execution_mapping</code>, <code>thread_execution_mapping</code> and <code>new_thread_execution_mapping</code> implies the relationship: <code>other_execution_mapping &lt; thread_execution_mapping &lt; new_thread_execution_mapping</code> <em>--end note</em>]</p>
<p>[<em>Note:</em> A mapping of an execution agent onto a thread of execution implies the agent executes as-if on a <code>std::thread</code>. Therefore, the facilities provided by <code>std::thread</code>, such as thread-local storage, are available. <code>new_thread_execution_mapping</code> provides stronger guarantees, in particular that thread-local storage will not be shared between execution agents. <em>--end note</em>]</p>
<h3 id="properties-for-customizing-memory-allocation"><span class="header-section-number">1.2.9</span> Properties for customizing memory allocation</h3>
<p>struct default_allocator_t {} default_allocator; template<class ProtoAllocator> struct allocator_wrapper_t { ProtoAllocator alloc; }; struct allocator_t { template<class ProtoAllocator> constexpr allocator_wrapper_t<ProtoAllocator> operator()(const ProtoAllocator&amp; a) { return {a}; } } allocator;</p>
<table style="width:36%;">
<colgroup>
<col width="15%" />
<col width="20%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Property</th>
<th align="left">Requirements</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>default_allocator</code></td>
<td align="left">Executor implementations shall use a default implmentation defined allocator to allocate any memory required to store the submitted function object.</td>
</tr>
<tr class="even">
<td align="left"><code>allocator(ProtoAllocator)</code></td>
<td align="left">Executor implementations shall use the supplied allocator to allocate any memory required to store the submitted function object.</td>
</tr>
</tbody>
</table>
<p>[<em>Note:</em> As the <code>allocator(ProtoAllocator)</code> property requires a value to be provided when being set, it is required to be implemented such that it is callable with the <code>ProtoAllocator</code> parameter when used in <code>require</code> or <code>prefer</code> where the customization points accepts the result of the function call operator of <code>allocator_t</code>; <code>allocator_wrapper_t</code> and is passable as an instance when used in <code>query</code> where the customization point accepts an instance of <code>allocator_t</code>. <em>--end note</em>]</p>
<p>[<em>Note:</em> It is permitted for an allocator provided via the <code>allocator(ProtoAllocator)</code> property to be the same type as the allocator provided by the <code>default_allocator</code> property. <em>--end note</em>]</p>
<h2 id="executor-type-traits"><span class="header-section-number">1.3</span> Executor type traits</h2>
<h3 id="determining-that-a-type-satisfies-executor-type-requirements"><span class="header-section-number">1.3.1</span> Determining that a type satisfies executor type requirements</h3>
<pre><code>template&lt;class T&gt; struct is_executor;
template&lt;class T&gt; struct is_oneway_executor;
template&lt;class T&gt; struct is_twoway_executor;
template&lt;class T&gt; struct is_then_executor;
template&lt;class T&gt; struct is_bulk_oneway_executor;
template&lt;class T&gt; struct is_bulk_twoway_executor;
template&lt;class T&gt; struct is_bulk_then_executor;</code></pre>
<p>This sub-clause contains templates that may be used to query the properties of a type at compile time. Each of these templates is a UnaryTypeTrait (C++Std [meta.rqmts]) with a BaseCharacteristic of <code>true_type</code> if the corresponding condition is true, otherwise <code>false_type</code>.</p>
<table style="width:94%;">
<colgroup>
<col width="40%" />
<col width="30%" />
<col width="23%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Template</th>
<th align="left">Condition</th>
<th align="left">Preconditions</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>template&lt;class T&gt;</code> <br/><code>struct is_executor</code></td>
<td align="left"><code>T</code> meets the syntactic requirements for <code>BaseExecutor</code>.</td>
<td align="left"><code>T</code> is a complete type.</td>
</tr>
<tr class="even">
<td align="left"><code>template&lt;class T&gt;</code> <br/><code>struct is_oneway_executor</code></td>
<td align="left"><code>T</code> meets the syntactic requirements for <code>OneWayExecutor</code>.</td>
<td align="left"><code>T</code> is a complete type.</td>
</tr>
<tr class="odd">
<td align="left"><code>template&lt;class T&gt;</code> <br/><code>struct is_twoway_executor</code></td>
<td align="left"><code>T</code> meets the syntactic requirements for <code>TwoWayExecutor</code>.</td>
<td align="left"><code>T</code> is a complete type.</td>
</tr>
<tr class="even">
<td align="left"><code>template&lt;class T&gt;</code> <br/><code>struct is_then_executor</code></td>
<td align="left"><code>T</code> meets the syntactic requirements for <code>ThenExecutor</code>.</td>
<td align="left"><code>T</code> is a complete type.</td>
</tr>
<tr class="odd">
<td align="left"><code>template&lt;class T&gt;</code> <br/><code>struct is_bulk_oneway_executor</code></td>
<td align="left"><code>T</code> meets the syntactic requirements for <code>BulkOneWayExecutor</code>.</td>
<td align="left"><code>T</code> is a complete type.</td>
</tr>
<tr class="even">
<td align="left"><code>template&lt;class T&gt;</code> <br/><code>struct is_bulk_twoway_executor</code></td>
<td align="left"><code>T</code> meets the syntactic requirements for <code>BulkTwoWayExecutor</code>.</td>
<td align="left"><code>T</code> is a complete type.</td>
</tr>
<tr class="odd">
<td align="left"><code>template&lt;class T&gt;</code> <br/><code>struct is_bulk_then_executor</code></td>
<td align="left"><code>T</code> meets the syntactic requirements for <code>BulkThenExecutor</code>.</td>
<td align="left"><code>T</code> is a complete type.</td>
</tr>
</tbody>
</table>
<h3 id="associated-execution-context-type"><span class="header-section-number">1.3.2</span> Associated execution context type</h3>
<pre><code>template&lt;class Executor&gt;
struct executor_context
{
  using type = std::decay_t&lt;decltype(declval&lt;const Executor&amp;&gt;().context())&gt;;
};</code></pre>
<h3 id="associated-future-type"><span class="header-section-number">1.3.3</span> Associated future type</h3>
<pre><code>template&lt;class Executor, class T&gt;
struct executor_future
{
  using type = decltype(execution::require(declval&lt;const Executor&amp;&gt;(), execution::twoway).twoway_execute(declval&lt;T(*)()&gt;()));
};</code></pre>
<h3 id="associated-shape-type"><span class="header-section-number">1.3.4</span> Associated shape type</h3>
<pre><code>template&lt;class Executor&gt;
struct executor_shape
{
  private:
    // exposition only
    template&lt;class T&gt;
    using helper = typename T::shape_type;

  public:
    using type = std::experimental::detected_or_t&lt;
      size_t, helper, decltype(execution::require(declval&lt;const Executor&amp;&gt;(), execution::bulk))
    &gt;;

    // exposition only
    static_assert(std::is_integral_v&lt;type&gt;, &quot;shape type must be an integral type&quot;);
};</code></pre>
<h3 id="associated-index-type"><span class="header-section-number">1.3.5</span> Associated index type</h3>
<pre><code>template&lt;class Executor&gt;
struct executor_index
{
  private:
    // exposition only
    template&lt;class T&gt;
    using helper = typename T::index_type;

  public:
    using type = std::experimental::detected_or_t&lt;
      executor_shape_t&lt;Executor&gt;, helper, decltype(execution::require(declval&lt;const Executor&amp;&gt;(), execution::bulk))
    &gt;;

    // exposition only
    static_assert(std::is_integral_v&lt;type&gt;, &quot;index type must be an integral type&quot;);
};</code></pre>
<h3 id="member-detection-type-traits-for-properties"><span class="header-section-number">1.3.6</span> Member detection type traits for properties</h3>
<pre><code>template&lt;class Executor, class Property&gt; struct has_require_member;
template&lt;class Executor, class Property&gt; struct has_query_member;</code></pre>
<p>This sub-clause contains templates that may be used to query the properties of a type at compile time. Each of these templates is a UnaryTypeTrait (C++Std [meta.rqmts]) with a BaseCharacteristic of <code>true_type</code> if the corresponding condition is true, otherwise <code>false_type</code>.</p>
<table style="width:94%;">
<colgroup>
<col width="40%" />
<col width="30%" />
<col width="23%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Template</th>
<th align="left">Condition</th>
<th align="left">Preconditions</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>template&lt;class Executor, class Property&gt;</code> <br/><code>struct has_require_member</code></td>
<td align="left">The expression <code>declval&lt;const Executor&gt;().require( declval&lt;Property&gt;())</code> is well formed.</td>
<td align="left"><code>Executor</code> is a complete type.</td>
</tr>
<tr class="even">
<td align="left"><code>template&lt;class Executor, class Property&gt;</code> <br/><code>struct has_query_member</code></td>
<td align="left">The expression <code>declval&lt;const Executor&gt;().query( declval&lt;Property&gt;())</code> is well formed.</td>
<td align="left"><code>Executor</code> is a complete type.</td>
</tr>
</tbody>
</table>
<h3 id="member-return-type-traits-for-properties"><span class="header-section-number">1.3.7</span> Member return type traits for properties</h3>
<pre><code>template&lt;class Executor, class Property&gt; struct require_member_result;
template&lt;class Executor, class Property&gt; struct query_member_result;</code></pre>
<p>This sub-clause contains templates that may be used to query the properties of a type at compile time. Each of these templates is a TransformationTrait (C++Std [meta.rqmts]).</p>
<table style="width:88%;">
<colgroup>
<col width="40%" />
<col width="30%" />
<col width="16%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Template</th>
<th align="left">Condition</th>
<th align="left">Comments</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>template&lt;class Executor, class Property&gt;</code> <br/><code>struct require_member_result</code></td>
<td align="left">The expression <code>declval&lt;const Executor&gt;().require( declval&lt;Property&gt;())</code> is well formed.</td>
<td align="left">The member typedef <code>type</code> shall name the type of the expression <code>declval&lt;const Executor&gt;().require( declval&lt;Property())</code>.</td>
</tr>
<tr class="even">
<td align="left"><code>template&lt;class Executor, class Property&gt;</code> <br/><code>struct query_member_result</code></td>
<td align="left">The expression <code>declval&lt;const Executor&gt;().query( declval&lt;Property&gt;())</code> is well formed.</td>
<td align="left">The member typedef <code>type</code> shall name the type of the expression <code>declval&lt;const Executor&gt;().query( declval&lt;Property())</code>.</td>
</tr>
</tbody>
</table>
<h2 id="property-value-types-traits-for-properties"><span class="header-section-number">1.4</span> Property value types traits for properties</h2>
<p>This sub-clause contains templates that may be used to query the properties of a type at compile time. Each of these templates is a TransformationTrait (C++Std [meta.rqmts]).</p>
<table style="width:88%;">
<colgroup>
<col width="40%" />
<col width="30%" />
<col width="16%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Template</th>
<th align="left">Condition</th>
<th align="left">Comments</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>template&lt;class Executor, class Property&gt;</code> <br/><code>struct property_value</code></td>
<td align="left"></td>
<td align="left">The member typedef <code>type</code> shall name the type of the value associated with the property <code>Property</code>.</td>
</tr>
</tbody>
</table>
<h2 id="executor-customization-points"><span class="header-section-number">1.5</span> Executor customization points</h2>
<p><em>Executor customization points</em> are functions which adapt an executor's properties. Executor customization points enable uniform use of executors in generic contexts.</p>
<p>When an executor customization point named <em>NAME</em> invokes a free execution function of the same name, overload resolution is performed in a context that includes the declaration <code>void</code> <em>NAME</em><code>(auto&amp;... args) = delete;</code>, where <code>sizeof...(args)</code> is the arity of the free execution function. This context also does not include a declaration of the executor customization point.</p>
<p>[<em>Note:</em> This provision allows executor customization points to call the executor's free, non-member execution function of the same name without recursion. <em>--end note</em>]</p>
<p>Whenever <code>std::experimental::concurrency_v2::execution::</code><em>NAME</em><code>(</code><em>ARGS</em><code>)</code> is a valid expression, that expression satisfies the syntactic requirements for the free execution function named <em>NAME</em> with arity <code>sizeof...(</code><em>ARGS</em><code>)</code> with that free execution function's semantics.</p>
<h3 id="require"><span class="header-section-number">1.5.1</span> <code>require</code></h3>
<pre><code>namespace {
  constexpr unspecified require = unspecified;
}</code></pre>
<p>The name <code>require</code> denotes a customization point. The effect of the expression <code>std::experimental::concurrency_v2::execution::require(E, P0, Pn...)</code> for some expressions <code>E</code> and <code>P0</code>, and where <code>Pn...</code> represents <code>N</code> expressions (where <code>N</code> is 0 or more), is equivalent to:</p>
<ul>
<li><p><code>(E).require(P0)</code> if <code>N == 0</code> and <code>has_require_member_v&lt;decay_t&lt;decltype(E)&gt;, decltype(P0)&gt;</code> is true.</p></li>
<li><p>Otherwise, <code>require(E, P0)</code> if <code>N == 0</code> and the expression is well formed.</p></li>
<li>Otherwise, <code>E</code> if <code>N == 0</code> and:</li>
<li><code>is_same&lt;decay_t&lt;decltype(P0)&gt;, oneway_t&gt;</code> is true and <code>(is_oneway_executor_v&lt;decay_t&lt;decltype(E)&gt;&gt; || is_bulk_oneway_executor_v&lt;decay_t&lt;decltype(E)&gt;&gt;)</code> is true; or</li>
<li><code>is_same&lt;decay_t&lt;decltype(P0)&gt;, twoway_t&gt;</code> is true and <code>(is_twoway_executor_v&lt;decay_t&lt;decltype(E)&gt;&gt; || is_bulk_twoway_executor_v&lt;decay_t&lt;decltype(E)&gt;&gt;)</code> is true; or</li>
<li><code>is_same&lt;decay_t&lt;decltype(P0)&gt;, single_t&gt;</code> is true and <code>(is_oneway_executor_v&lt;decay_t&lt;decltype(E)&gt;&gt; || is_twoway_executor_v&lt;decay_t&lt;decltype(E)&gt;&gt;)</code> is true; or</li>
<li><code>is_same&lt;decay_t&lt;decltype(P0)&gt;, bulk_t&gt;</code> is true and <code>(is_bulk_oneway_executor_v&lt;decay_t&lt;decltype(E)&gt;&gt; || is_bulk_twoway_executor_v&lt;decay_t&lt;decltype(E)&gt;&gt;)</code> is true; or</li>
<li><p><code>is_same&lt;decay_t&lt;decltype(P0)&gt;, possibly_blocking_t&gt;</code> is true.</p></li>
<li><p>Otherwise, a value <code>E1</code> of unspecified type that holds a copy of <code>E</code> if <code>N == 0</code>, <code>is_same&lt;decay_t&lt;decltype(P0)&gt;, twoway_t&gt;</code> is true, and <code>can_query_v&lt;decltype(E), adaptable_blocking_t&gt;</code> is true. The type of <code>E1</code> satisfies the <code>BaseExecutor</code> requirements and provides member functions such that calls to <code>require</code>, <code>prefer</code>, <code>query</code>, <code>context</code>, <code>execute</code> and <code>bulk_execute</code> are forwarded to the corresponding member functions of the copy of <code>E</code>, if present. In addition, if <code>E</code> satisfies the <code>OneWayExecutor</code> requirements, <code>E1</code> shall satisfy the <code>TwoWayExecutor</code> requirements by implementing <code>twoway_execute</code> in terms of <code>execute</code>. Similarly, if <code>E</code> satisfies the <code>BulkOneWayExecutor</code> requirements, <code>E1</code> shall satisfy the <code>BulkTwoWayExecutor</code> requirements by implementing <code>bulk_twoway_execute</code> in terms of <code>bulk_execute</code>. For some type <code>T</code>, the type yielded by <code>executor_future_t&lt;decltype(E1), T&gt;</code> is <code>std::experimental::future&lt;T&gt;</code>. <code>E1</code> has the same executor properties as <code>E</code>, except for the addition of the <code>twoway_t</code> property.</p></li>
<li><p>Otherwise, a value <code>E1</code> of unspecified type that holds a copy of <code>E</code> if <code>N == 0</code> and <code>is_same&lt;decay_t&lt;decltype(P0)&gt;, bulk_t&gt;</code> is true. The type of <code>E1</code> satisfies the <code>BaseExecutor</code> requirements and provides member functions such that calls to <code>require</code>, <code>prefer</code>, <code>query</code>, <code>context</code>, <code>execute</code> and <code>twoway_execute</code> are forwarded to the corresponding member functions of the copy of <code>E</code>, if present. In addition, if <code>E</code> satisfies the <code>OneWayExecutor</code> requirements, <code>E1</code> shall satisfy the <code>BulkExecutor</code> requirements by implementing <code>bulk_execute</code> in terms of <code>execute</code>. If <code>E</code> also satisfies the <code>TwoWayExecutor</code> requirements, <code>E1</code> shall satisfy the <code>BulkTwoWayExecutor</code> requirements by implementing <code>bulk_twoway_execute</code> in terms of <code>bulk_execute</code>. <code>E1</code> has the same executor properties as <code>E</code>, except for the addition of the <code>bulk_t</code> property.</p></li>
<li><p>Otherwise, a value <code>E1</code> of unspecified type that holds a copy of <code>E</code> if <code>N == 0</code>, <code>is_same&lt;decay_t&lt;decltype(P0)&gt;, always_blocking_t&gt;</code> is true, and <code>can_query_v&lt;decltype(E), adaptable_blocking_t&gt;</code> is true. The type of <code>E1</code> satisfies the <code>BaseExecutor</code> requirements and provides member functions such that calls to <code>require</code>, <code>prefer</code>, <code>query</code>, <code>context</code>, <code>execute</code>, <code>twoway_execute</code>, <code>bulk_execute</code>, and <code>bulk_twoway_execute</code> are forwarded to the corresponding member functions of the copy of <code>E</code>, if present. In addition, <code>E1</code> provides an overload of <code>require</code> that returns a copy of <code>E1</code>, and all functions <code>execute</code>, <code>twoway_execute</code>, <code>bulk_execute</code>, and <code>bulk_twoway_execute</code> shall block the calling thread until the submitted functions have finished execution. <code>E1</code> has the same executor properties as <code>E</code>, except for the addition of the <code>always_blocking_t</code> property, and removal of <code>never_blocking_t</code> and <code>possibly_blocking_t</code> properties if present.</p></li>
<li><p>Otherwise, a value <code>E1</code> of unspecified type that holds a copy of <code>E</code> if <code>N == 0</code> and <code>is_same&lt;decay_t&lt;decltype(P0)&gt;, adaptable_blocking_t&gt;</code> is true. The type of <code>E1</code> satisfies the <code>BaseExecutor</code> requirements and provides member functions such that calls to <code>require</code>, <code>prefer</code>, <code>query</code>, <code>context</code>, <code>execute</code>, <code>twoway_execute</code>, <code>bulk_execute</code>, and <code>bulk_twoway_execute</code> are forwarded to the corresponding member functions of the copy of <code>E</code>, if present. In addition, <code>can_query_v&lt;decltype(E1), adaptable_blocking_t&gt;</code> is true, and <code>E1.require(not_adaptable_blocking_t)</code> yields a copy of <code>E</code>. <code>E1</code> has the same executor properties as <code>E</code>, except for the addition of the <code>adaptable_blocking_t</code> property.</p></li>
<li><p>Otherwise, <code>std::experimental::concurrency_v2::execution::require( std::experimental::concurrency_v2::execution::require(E, P0), Pn...)</code> if <code>N &gt; 0</code> and the expression is well formed.</p></li>
<li><p>Otherwise, <code>std::experimental::concurrency_v2::execution::require(E, P0, Pn...)</code> is ill-formed.</p></li>
</ul>
<h3 id="prefer"><span class="header-section-number">1.5.2</span> <code>prefer</code></h3>
<pre><code>namespace {
  constexpr unspecified prefer = unspecified;
}</code></pre>
<p>The name <code>prefer</code> denotes a customization point. The effect of the expression <code>std::experimental::concurrency_v2::execution::prefer(E, P0, Pn...)</code> for some expressions <code>E</code> and <code>P0</code>, and where <code>Pn...</code> represents <code>N</code> expressions (where <code>N</code> is 0 or more), is equivalent to:</p>
<ul>
<li><p><code>(E).require(P0)</code> if <code>N == 0</code> and <code>has_require_member_v&lt;decay_t&lt;decltype(E)&gt;, decltype(P0)&gt;</code> is true.</p></li>
<li><p>Otherwise, <code>prefer(E, P0)</code> if <code>N == 0</code> and the expression is well formed.</p></li>
<li><p>Otherwise, <code>E</code> if <code>N == 0</code>.</p></li>
<li><p>Otherwise, <code>std::experimental::concurrency_v2::execution::prefer( std::experimental::concurrency_v2::execution::prefer(E, P0), Pn...)</code> if the expression is well formed.</p></li>
<li><p>Otherwise, <code>std::experimental::concurrency_v2::execution::prefer(E, P0, Pn...)</code> is ill-formed.</p></li>
</ul>
<p>When the executor customization point named <code>prefer</code> invokes a free execution function of the same name, overload resolution is performed in a context that includes the declarations:</p>
<pre><code>template&lt;class E&gt; void prefer(const E&amp;, const oneway_t&amp;) = delete;
template&lt;class E&gt; void prefer(const E&amp;, const twoway_t&amp;) = delete;
template&lt;class E&gt; void prefer(const E&amp;, const single_t&amp;) = delete;
template&lt;class E&gt; void prefer(const E&amp;, const bulk_t&amp;) = delete;</code></pre>
<p>[<em>Note:</em> This prevents the <code>oneway_t</code>, <code>twoway_t</code>, <code>single_t</code>, and <code>bulk_t</code> properties from being expressed as preferences. They may be used only as requirements. <em>--end note</em>]</p>
<h3 id="query"><span class="header-section-number">1.5.3</span> <code>query</code></h3>
<pre><code>namespace {
  constexpr unspecified query = unspecified;
}</code></pre>
<p>The name <code>query</code> denotes a customization point. The effect of the expression <code>std::experimental::concurrency_v2::execution::query(E, P)</code> for some expressions <code>E</code> and <code>P</code> is equivalent to:</p>
<ul>
<li><p><code>(E).query(P)</code> if <code>has_query_member_v&lt;decay_t&lt;decltype(E)&gt;, decltype(P)&gt;</code> is true.</p></li>
<li><p>Otherwise, <code>query(E, P)</code> if the expression is well formed.</p></li>
<li><p>Otherwise, <code>std::experimental::concurrency_v2::execution::query(E, P)</code> is ill-formed.</p></li>
</ul>
<h3 id="customization-point-type-traits"><span class="header-section-number">1.5.4</span> Customization point type traits</h3>
<pre><code>template&lt;class Executor, class... Properties&gt; struct can_require;
template&lt;class Executor, class... Properties&gt; struct can_prefer;
template&lt;class Executor, class Property&gt; struct can_query;</code></pre>
<p>This sub-clause contains templates that may be used to query the properties of a type at compile time. Each of these templates is a UnaryTypeTrait (C++Std [meta.rqmts]) with a BaseCharacteristic of <code>true_type</code> if the corresponding condition is true, otherwise <code>false_type</code>.</p>
<table style="width:94%;">
<colgroup>
<col width="40%" />
<col width="30%" />
<col width="23%" />
</colgroup>
<thead>
<tr class="header">
<th align="left">Template</th>
<th align="left">Condition</th>
<th align="left">Preconditions</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left"><code>template&lt;class T&gt;</code> <br/><code>struct can_require</code></td>
<td align="left">The expression <code>std::experimental::concurrency_v2::execution::require( declval&lt;const Executor&gt;(), declval&lt;Properties&gt;()...)</code> is well formed.</td>
<td align="left"><code>T</code> is a complete type.</td>
</tr>
<tr class="even">
<td align="left"><code>template&lt;class T&gt;</code> <br/><code>struct can_prefer</code></td>
<td align="left">The expression <code>std::experimental::concurrency_v2::execution::prefer( declval&lt;const Executor&gt;(), declval&lt;Properties&gt;()...)</code> is well formed.</td>
<td align="left"><code>T</code> is a complete type.</td>
</tr>
<tr class="odd">
<td align="left"><code>template&lt;class T&gt;</code> <br/><code>struct can_query</code></td>
<td align="left">The expression <code>std::experimental::concurrency_v2::execution::query( declval&lt;const Executor&gt;(), declval&lt;Property&gt;())</code> is well formed.</td>
<td align="left"><code>T</code> is a complete type.</td>
</tr>
</tbody>
</table>
<h2 id="polymorphic-executor-wrappers"><span class="header-section-number">1.6</span> Polymorphic executor wrappers</h2>
<h3 id="class-bad_executor"><span class="header-section-number">1.6.1</span> Class <code>bad_executor</code></h3>
<p>An exception of type <code>bad_executor</code> is thrown by <code>executor</code> member functions <code>execute</code>, <code>twoway_execute</code>, <code>bulk_execute</code>, and <code>bulk_twoway_execute</code> when the executor object has no target.</p>
<pre><code>class bad_executor : public exception
{
public:
  // constructor:
  bad_executor() noexcept;
};</code></pre>
<h4 id="bad_executor-constructors"><span class="header-section-number">1.6.1.1</span> <code>bad_executor</code> constructors</h4>
<pre><code>bad_executor() noexcept;</code></pre>
<p><em>Effects:</em> Constructs a <code>bad_executor</code> object.</p>
<p><em>Postconditions:</em> <code>what()</code> returns an implementation-defined NTBS.</p>
<h3 id="class-executor"><span class="header-section-number">1.6.2</span> Class <code>executor</code></h3>
<p>The <code>executor</code> class provides a polymorphic wrapper for executor types.</p>
<pre><code>class executor
{
public:
  class context_type;

  // construct / copy / destroy:

  executor() noexcept;
  executor(nullptr_t) noexcept;
  executor(const executor&amp; e) noexcept;
  executor(executor&amp;&amp; e) noexcept;
  template&lt;class Executor&gt; executor(Executor e);

  executor&amp; operator=(const executor&amp; e) noexcept;
  executor&amp; operator=(executor&amp;&amp; e) noexcept;
  executor&amp; operator=(nullptr_t) noexcept;
  template&lt;class Executor&gt; executor&amp; operator=(Executor e);

  ~executor();

  // executor modifiers:

  void swap(executor&amp; other) noexcept;

  // executor operations:

  const context_type&amp; context() const noexcept;

  executor require(oneway_t) const;
  executor require(twoway_t) const;
  executor require(single_t) const;
  executor require(bulk_t) const;
  executor require(thread_execution_mapping_t) const;
  executor require(never_blocking_t p) const;
  executor require(possibly_blocking_t p) const;
  executor require(always_blocking_t p) const;

  template&lt;class Function&gt;
    void execute(Function&amp;&amp; f) const;

  template&lt;class Function&gt;
    std::experimental::future&lt;result_of_t&lt;decay_t&lt;Function&gt;()&gt;&gt;
      twoway_execute(Function&amp;&amp; f) const

  template&lt;class Function, class SharedFactory&gt;
    void bulk_execute(Function&amp;&amp; f, size_t n, SharedFactory&amp;&amp; sf) const;

  template&lt;class Function, class ResultFactory, class SharedFactory&gt;
    std::experimental::future&lt;result_of_t&lt;decay_t&lt;ResultFactory&gt;()&gt;&gt;
      bulk_twoway_execute(Function&amp;&amp; f, size_t n, ResultFactory&amp;&amp; rf, SharedFactory&amp;&amp; sf) const;

  // executor capacity:

  explicit operator bool() const noexcept;

  // executor target access:

  const type_info&amp; target_type() const noexcept;
  template&lt;class Executor&gt; Executor* target() noexcept;
  template&lt;class Executor&gt; const Executor* target() const noexcept;
};

// executor comparisons:

bool operator==(const executor&amp; a, const executor&amp; b) noexcept;
bool operator==(const executor&amp; e, nullptr_t) noexcept;
bool operator==(nullptr_t, const executor&amp; e) noexcept;
bool operator!=(const executor&amp; a, const executor&amp; b) noexcept;
bool operator!=(const executor&amp; e, nullptr_t) noexcept;
bool operator!=(nullptr_t, const executor&amp; e) noexcept;

// executor specialized algorithms:

void swap(executor&amp; a, executor&amp; b) noexcept;

executor prefer(const executor&amp; e, continuation_t p);
executor prefer(const executor&amp; e, not_continuation_t p);
executor prefer(const executor&amp; e, outstanding_work_t p);
executor prefer(const executor&amp; e, not_outstanding_work_t p);
executor prefer(const executor&amp; e, bulk_sequenced_execution_t p);
executor prefer(const executor&amp; e, bulk_parallel_execution_t p);
executor prefer(const executor&amp; e, bulk_unsequenced_execution_t p);
executor prefer(const executor&amp; e, new_thread_execution_mapping_t p);</code></pre>
<p>The <code>executor</code> class satisfies the <code>BaseExecutor</code>, <code>DefaultConstructible</code> (C++Std [defaultconstructible]), and <code>CopyAssignable</code> (C++Std [copyassignable]) requirements.</p>
<p>[<em>Note:</em> To meet the <code>noexcept</code> requirements for executor copy constructors and move constructors, implementations may share a target between two or more <code>executor</code> objects. <em>--end note</em>]</p>
<p>The <em>target</em> is the executor object that is held by the wrapper.</p>
<h4 id="executor-constructors"><span class="header-section-number">1.6.2.1</span> <code>executor</code> constructors</h4>
<pre><code>executor() noexcept;</code></pre>
<p><em>Postconditions:</em> <code>!*this</code>.</p>
<pre><code>executor(nullptr_t) noexcept;</code></pre>
<p><em>Postconditions:</em> <code>!*this</code>.</p>
<pre><code>executor(const executor&amp; e) noexcept;</code></pre>
<p><em>Postconditions:</em> <code>!*this</code> if <code>!e</code>; otherwise, <code>*this</code> targets <code>e.target()</code> or a copy of <code>e.target()</code>.</p>
<pre><code>executor(executor&amp;&amp; e) noexcept;</code></pre>
<p><em>Effects:</em> If <code>!e</code>, <code>*this</code> has no target; otherwise, moves <code>e.target()</code> or move-constructs the target of <code>e</code> into the target of <code>*this</code>, leaving <code>e</code> in a valid state with an unspecified value.</p>
<pre><code>template&lt;class Executor&gt; executor(Executor e);</code></pre>
<p><em>Requires:</em></p>
<ul>
<li><code>can_require_v&lt;Executor, oneway&gt;</code></li>
<li><code>can_require_v&lt;Executor, twoway&gt;</code></li>
<li><code>can_require_v&lt;Executor, single&gt;</code></li>
<li><code>can_require_v&lt;Executor, bulk&gt;</code></li>
<li><code>can_require_v&lt;Executor, never_blocking&gt;</code></li>
<li><code>can_require_v&lt;Executor, possibly_blocking&gt;</code></li>
<li><code>can_require_v&lt;Executor, always_blocking&gt;</code></li>
<li><code>can_prefer_v&lt;Executor, continuation&gt;</code></li>
<li><code>can_prefer_v&lt;Executor, not_continuation&gt;</code></li>
<li><code>can_prefer_v&lt;Executor, outstanding_work&gt;</code></li>
<li><code>can_prefer_v&lt;Executor, not_outstanding_work&gt;</code></li>
<li><code>can_prefer_v&lt;Executor, caller_parallel_execution&gt;</code></li>
<li><code>can_prefer_v&lt;Executor, caller_weakly_parallel_execution&gt;</code></li>
<li><code>can_prefer_v&lt;Executor, caller_concurrent_execution&gt;</code></li>
<li><code>can_prefer_v&lt;Executor, bulk_sequenced_execution&gt;</code></li>
<li><code>can_prefer_v&lt;Executor, bulk_parallel_execution&gt;</code></li>
<li><code>can_prefer_v&lt;Executor, bulk_unsequenced_execution&gt;</code></li>
<li><code>can_prefer_v&lt;Executor, thread_execution_mapping&gt;</code></li>
<li><code>can_prefer_v&lt;Executor, new_thread_execution_mapping&gt;</code></li>
</ul>
<p><em>Effects:</em> <code>*this</code> targets a copy of <code>e</code> initialized with <code>std::move(e)</code>.</p>
<h4 id="executor-assignment"><span class="header-section-number">1.6.2.2</span> <code>executor</code> assignment</h4>
<pre><code>executor&amp; operator=(const executor&amp; e) noexcept;</code></pre>
<p><em>Effects:</em> <code>executor(e).swap(*this)</code>.</p>
<p><em>Returns:</em> <code>*this</code>.</p>
<pre><code>executor&amp; operator=(executor&amp;&amp; e) noexcept;</code></pre>
<p><em>Effects:</em> Replaces the target of <code>*this</code> with the target of <code>e</code>, leaving <code>e</code> in a valid state with an unspecified value.</p>
<p><em>Returns:</em> <code>*this</code>.</p>
<pre><code>executor&amp; operator=(nullptr_t) noexcept;</code></pre>
<p><em>Effects:</em> <code>executor(nullptr).swap(*this)</code>.</p>
<p><em>Returns:</em> <code>*this</code>.</p>
<pre><code>template&lt;class Executor&gt; executor&amp; operator=(Executor e);</code></pre>
<p><em>Requires:</em> As for <code>template&lt;class Executor&gt; executor(Executor e)</code>.</p>
<p><em>Effects:</em> <code>executor(std::move(e)).swap(*this)</code>.</p>
<p><em>Returns:</em> <code>*this</code>.</p>
<h4 id="executor-destructor"><span class="header-section-number">1.6.2.3</span> <code>executor</code> destructor</h4>
<pre><code>~executor();</code></pre>
<p><em>Effects:</em> If <code>*this != nullptr</code>, releases shared ownership of, or destroys, the target of <code>*this</code>.</p>
<h4 id="executor-modifiers"><span class="header-section-number">1.6.2.4</span> <code>executor</code> modifiers</h4>
<pre><code>void swap(executor&amp; other) noexcept;</code></pre>
<p><em>Effects:</em> Interchanges the targets of <code>*this</code> and <code>other</code>.</p>
<h4 id="executor-operations"><span class="header-section-number">1.6.2.5</span> <code>executor</code> operations</h4>
<pre><code>const context_type&amp; context() const noexcept;</code></pre>
<p><em>Requires:</em> <code>*this != nullptr</code>.</p>
<p><em>Returns:</em> A polymorphic execution context wrapper whose target is <code>e.context()</code>, where <code>e</code> is the target object of <code>*this</code>.</p>
<pre><code>executor require(oneway_t) const;
executor require(twoway_t) const;
executor require(single_t) const;
executor require(bulk_t) const;
executor require(thread_execution_mapping_t) const;</code></pre>
<p><em>Returns:</em> <code>*this</code>.</p>
<pre><code>executor require(never_blocking_t p) const;
executor require(possibly_blocking_t p) const;
executor require(always_blocking_t p) const;</code></pre>
<p><em>Returns:</em> A polymorphic wrapper whose target is <code>execution::require(e, p)</code>, where <code>e</code> is the target object of <code>*this</code>.</p>
<pre><code>template&lt;class Function&gt;
  void execute(Function&amp;&amp; f) const;</code></pre>
<p><em>Effects:</em> Performs <code>e2.execute(f2)</code>, where:</p>
<ul>
<li><code>e1</code> is the target object of <code>*this</code>;</li>
<li><code>e2</code> is the result of <code>require(require(e1, single), oneway)</code>;</li>
<li><code>f1</code> is the result of <code>DECAY_COPY(std::forward&lt;Function&gt;(f))</code>;</li>
<li><code>f2</code> is a function object of unspecified type that, when called as <code>f2()</code>, performs <code>f1()</code>.</li>
</ul>
<pre><code>template&lt;class Function&gt;
  std::experimental::future&lt;result_of_t&lt;decay_t&lt;Function&gt;()&gt;&gt;
    twoway_execute(Function&amp;&amp; f) const</code></pre>
<p><em>Effects:</em> Performs <code>e2.twoway_execute(f2)</code>, where:</p>
<ul>
<li><code>e1</code> is the target object of <code>*this</code>;</li>
<li><code>e2</code> is the result of <code>require(require(e1, single), twoway)</code>;</li>
<li><code>f1</code> is the result of <code>DECAY_COPY(std::forward&lt;Function&gt;(f))</code>;</li>
<li><code>f2</code> is a function object of unspecified type that, when called as <code>f2()</code>, performs <code>f1()</code>.</li>
</ul>
<p><em>Returns:</em> A future, whose shared state is made ready when the future returned by <code>e.twoway_execute(f2)</code> is made ready, containing the result of <code>f1()</code> or any exception thrown by <code>f1()</code>. [<em>Note:</em> <code>e2.twoway_execute(f2)</code> may return any future type that satisfies the Future requirements, and not necessarily <code>std::experimental::future</code>. One possible implementation approach is for the polymorphic wrapper to attach a continuation to the inner future via that object's <code>then()</code> member function. When invoked, this continuation stores the result in the outer future's associated shared and makes that shared state ready. <em>--end note</em>]</p>
<pre><code>template&lt;class Function, class SharedFactory&gt;
  void bulk_execute(Function&amp;&amp; f, size_t n, SharedFactory&amp;&amp; sf) const;</code></pre>
<p><em>Effects:</em> Performs <code>e2.bulk_execute(f2, n, sf2)</code>, where:</p>
<ul>
<li><code>e1</code> is the target object of <code>*this</code>;</li>
<li><code>e2</code> is the result of <code>require(require(e1, bulk), oneway)</code>;</li>
<li><code>sf1</code> is the result of <code>DECAY_COPY(std::forward&lt;SharedFactory&gt;(sf))</code>;</li>
<li><code>sf2</code> is a function object of unspecified type that, when called as <code>sf2()</code>, performs <code>sf1()</code>;</li>
<li><code>s1</code> is the result of <code>sf1()</code>;</li>
<li><code>s2</code> is the result of <code>sf2()</code>;</li>
<li><code>f1</code> is the result of <code>DECAY_COPY(std::forward&lt;Function&gt;(f))</code>;</li>
<li><code>f2</code> is a function object of unspecified type that, when called as <code>f2(i, s2)</code>, performs <code>f1(i, s1)</code>, where <code>i</code> is a value of type <code>size_t</code>.</li>
</ul>
<pre><code>template&lt;class Function, class ResultFactory, class SharedFactory&gt;
  std::experimental::future&lt;result_of_t&lt;decay_t&lt;ResultFactory&gt;()&gt;&gt;
    void bulk_twoway_execute(Function&amp;&amp; f, size_t n, ResultFactory&amp;&amp; rf, SharedFactory&amp;&amp; sf) const;</code></pre>
<p><em>Effects:</em> Performs <code>e.bulk_twoway_execute(f2, n, rf2, sf2)</code>, where:</p>
<ul>
<li><code>e1</code> is the target object of <code>*this</code>;</li>
<li><code>e2</code> is the result of <code>require(require(e1, bulk), twoway)</code>;</li>
<li><code>rf1</code> is the result of <code>DECAY_COPY(std::forward&lt;ResultFactory&gt;(rf))</code>;</li>
<li><code>rf2</code> is a function object of unspecified type that, when called as <code>rf2()</code>, performs <code>rf1()</code>;</li>
<li><code>sf1</code> is the result of <code>DECAY_COPY(std::forward&lt;SharedFactory&gt;(rf))</code>;</li>
<li><code>sf2</code> is a function object of unspecified type that, when called as <code>sf2()</code>, performs <code>sf1()</code>;</li>
<li>if <code>decltype(rf1())</code> is non-void, <code>r1</code> is the result of <code>rf1()</code>;</li>
<li>if <code>decltype(rf2())</code> is non-void, <code>r2</code> is the result of <code>rf2()</code>;</li>
<li><code>s1</code> is the result of <code>sf1()</code>;</li>
<li><code>s2</code> is the result of <code>sf2()</code>;</li>
<li><code>f1</code> is the result of <code>DECAY_COPY(std::forward&lt;Function&gt;(f))</code>;</li>
<li>if <code>decltype(rf1())</code> is non-void and <code>decltype(rf2())</code> is non-void, <code>f2</code> is a function object of unspecified type that, when called as <code>f2(i, r2, s2)</code>, performs <code>f1(i, r1, s1)</code>, where <code>i</code> is a value of type <code>size_t</code>.</li>
<li>if <code>decltype(rf1())</code> is non-void and <code>decltype(rf2())</code> is void, <code>f2</code> is a function object of unspecified type that, when called as <code>f2(i, s2)</code>, performs <code>f1(i, r1, s1)</code>, where <code>i</code> is a value of type <code>size_t</code>.</li>
<li>if <code>decltype(rf1())</code> is void and <code>decltype(rf2())</code> is non-void, <code>f2</code> is a function object of unspecified type that, when called as <code>f2(i, r2, s2)</code>, performs <code>f1(i, s1)</code>, where <code>i</code> is a value of type <code>size_t</code>.</li>
<li>if <code>decltype(rf1())</code> is void and <code>decltype(rf2())</code> is void, <code>f2</code> is a function object of unspecified type that, when called as <code>f2(i, s2)</code>, performs <code>f1(i, s1)</code>, where <code>i</code> is a value of type <code>size_t</code>.</li>
</ul>
<p><em>Returns:</em> A future, whose shared state is made ready when the future returned by <code>e.bulk_twoway_execute(f2, n, rf2, sf2)</code> is made ready, containing the result in <code>r1</code> (if <code>decltype(rf1())</code> is non-void) or any exception thrown by an invocation<code>f1</code>. [<em>Note:</em> <code>e2.bulk_twoway_execute(f2)</code> may return any future type that satisfies the Future requirements, and not necessarily <code>std::experimental::future</code>. One possible implementation approach is for the polymorphic wrapper to attach a continuation to the inner future via that object's <code>then()</code> member function. When invoked, this continuation stores the result in the outer future's associated shared and makes that shared state ready. <em>--end note</em>]</p>
<h4 id="executor-capacity"><span class="header-section-number">1.6.2.6</span> <code>executor</code> capacity</h4>
<pre><code>explicit operator bool() const noexcept;</code></pre>
<p><em>Returns:</em> <code>true</code> if <code>*this</code> has a target, otherwise <code>false</code>.</p>
<h4 id="executor-target-access"><span class="header-section-number">1.6.2.7</span> <code>executor</code> target access</h4>
<pre><code>const type_info&amp; target_type() const noexcept;</code></pre>
<p><em>Returns:</em> If <code>*this</code> has a target of type <code>T</code>, <code>typeid(T)</code>; otherwise, <code>typeid(void)</code>.</p>
<pre><code>template&lt;class Executor&gt; Executor* target() noexcept;
template&lt;class Executor&gt; const Executor* target() const noexcept;</code></pre>
<p><em>Returns:</em> If <code>target_type() == typeid(Executor)</code> a pointer to the stored executor target; otherwise a null pointer value.</p>
<h4 id="executor-comparisons"><span class="header-section-number">1.6.2.8</span> <code>executor</code> comparisons</h4>
<pre><code>bool operator==(const executor&amp; a, const executor&amp; b) noexcept;</code></pre>
<p><em>Returns:</em></p>
<ul>
<li><code>true</code> if <code>!a</code> and <code>!b</code>;</li>
<li><code>true</code> if <code>a</code> and <code>b</code> share a target;</li>
<li><code>true</code> if <code>e</code> and <code>f</code> are the same type and <code>e == f</code>, where <code>e</code> is the target of <code>a</code> and <code>f</code> is the target of <code>b</code>;</li>
<li>otherwise <code>false</code>.</li>
</ul>
<pre><code>bool operator==(const executor&amp; e, nullptr_t) noexcept;
bool operator==(nullptr_t, const executor&amp; e) noexcept;</code></pre>
<p><em>Returns:</em> <code>!e</code>.</p>
<pre><code>bool operator!=(const executor&amp; a, const executor&amp; b) noexcept;</code></pre>
<p><em>Returns:</em> <code>!(a == b)</code>.</p>
<pre><code>bool operator!=(const executor&amp; e, nullptr_t) noexcept;
bool operator!=(nullptr_t, const executor&amp; e) noexcept;</code></pre>
<p><em>Returns:</em> <code>(bool) e</code>.</p>
<h4 id="executor-specialized-algorithms"><span class="header-section-number">1.6.2.9</span> <code>executor</code> specialized algorithms</h4>
<pre><code>void swap(executor&amp; a, executor&amp; b) noexcept;</code></pre>
<p><em>Effects:</em> <code>a.swap(b)</code>.</p>
<pre><code>executor prefer(const executor&amp; e, continuation_t p);
executor prefer(const executor&amp; e, not_continuation_t p);
executor prefer(const executor&amp; e, outstanding_work_t p);
executor prefer(const executor&amp; e, not_outstanding_work_t p);
executor prefer(const executor&amp; e, bulk_sequenced_execution_t p);
executor prefer(const executor&amp; e, bulk_parallel_execution_t p);
executor prefer(const executor&amp; e, bulk_unsequenced_execution_t p);
executor prefer(const executor&amp; e, new_thread_execution_mapping_t p);</code></pre>
<p><em>Returns:</em> A polymorphic wrapper whose target is <code>execution::prefer(e1, p)</code>, where <code>e1</code> is the target object of <code>e</code>.</p>
<h3 id="class-executorcontext_type"><span class="header-section-number">1.6.3</span> Class <code>executor::context_type</code></h3>
<p>The <code>executor::context_type</code> class provides a polymorphic wrapper for the execution context associated with a polymorphic executor.</p>
<pre><code>class executor::context_type
{
public:
  context_type(const context_type&amp;) = delete;
  context_type&amp; operator=(const context_type&amp;) = delete;
};

// executor context_type comparisons:

bool operator==(const executor::context_type&amp; a, const executor::context_type&amp; b) noexcept;
template&lt;class Context&gt; operator==(const executor::context_type&amp; a, const Context&amp; b) noexcept;
template&lt;class Context&gt; operator==(const Context&amp; a, const executor::context_type&amp; b) noexcept;
bool operator!=(const executor::context_type&amp; a, const executor::context_type&amp; b) noexcept;
template&lt;class Context&gt; operator!=(const executor::context_type&amp; a, const Context&amp; b) noexcept;
template&lt;class Context&gt; operator!=(const Context&amp; a, const executor::context_type&amp; b) noexcept;</code></pre>
<p>The <em>target</em> is the execution context that is associated with the target of the <code>executor</code> that created the <code>context_type</code> wrapper.</p>
<h4 id="executorcontext_type-comparisons"><span class="header-section-number">1.6.3.1</span> <code>executor::context_type</code> comparisons</h4>
<pre><code>bool operator==(const executor::context_type&amp; a, const executor::context_type&amp; b) noexcept;</code></pre>
<p><em>Returns:</em> - <code>true</code> if <code>!a</code> and <code>!b</code>; - <code>true</code> if <code>a</code> and <code>b</code> share a target; - <code>true</code> if <code>c</code> and <code>d</code> are the same type and <code>c == d</code>, where <code>c</code> is the target of <code>a</code> and <code>d</code> is the target of <code>b</code>; - otherwise <code>false</code>.</p>
<pre><code>template&lt;class Context&gt; operator==(const executor::context_type&amp; a, const Context&amp; b) noexcept;</code></pre>
<p><em>Returns:</em> - <code>true</code> if <code>c</code> and <code>b</code> are the same type and <code>c == b</code>, where <code>c</code> is the target of <code>a</code>; - otherwise <code>false</code>.</p>
<pre><code>template&lt;class Context&gt; operator==(const Context&amp; a, const executor::context_type&amp; b) noexcept;</code></pre>
<p><em>Returns:</em> <code>b == a</code>.</p>
<pre><code>bool operator!=(const executor::context_type&amp; a, const executor::context_type&amp; b) noexcept;
template&lt;class Context&gt; operator!=(const executor::context_type&amp; a, const Context&amp; b) noexcept;
template&lt;class Context&gt; operator!=(const Context&amp; a, const executor::context_type&amp; b) noexcept;</code></pre>
<p><em>Returns:</em> <code>!(a == b)</code>.</p>
<h2 id="thread-pools"><span class="header-section-number">1.7</span> Thread pools</h2>
<p>Thread pools create execution agents which execute on threads without incurring the overhead of thread creation and destruction whenever such agents are needed.</p>
<h3 id="header-thread_pool-synopsis"><span class="header-section-number">1.7.1</span> Header <code>&lt;thread_pool&gt;</code> synopsis</h3>
<pre><code>namespace std {
namespace experimental {
inline namespace concurrency_v2 {

  class static_thread_pool;

} // inline namespace concurrency_v2
} // namespace experimental
} // namespace std</code></pre>
<h3 id="class-static_thread_pool"><span class="header-section-number">1.7.2</span> Class <code>static_thread_pool</code></h3>
<p><code>static_thread_pool</code> is a statically-sized thread pool which may be explicitly grown via thread attachment. The <code>static_thread_pool</code> is expected to be created with the use case clearly in mind with the number of threads known by the creator. As a result, no default constructor is considered correct for arbitrary use cases and <code>static_thread_pool</code> does not support any form of automatic resizing.</p>
<p><code>static_thread_pool</code> presents an effectively unbounded input queue and the execution functions of <code>static_thread_pool</code>'s associated executors do not block on this input queue.</p>
<p>[<em>Note:</em> Because <code>static_thread_pool</code> provides parallel execution agents, situations which require concurrent execution properties are not guaranteed correctness. <em>--end note.</em>]</p>
<pre><code>class static_thread_pool
{
  public:
    using executor_type = see-below;
    
    // construction/destruction
    explicit static_thread_pool(std::size_t num_threads);
    
    // nocopy
    static_thread_pool(const static_thread_pool&amp;) = delete;
    static_thread_pool&amp; operator=(const static_thread_pool&amp;) = delete;

    // stop accepting incoming work and wait for work to drain
    ~static_thread_pool();

    // attach current thread to the thread pools list of worker threads
    void attach();

    // signal all work to complete
    void stop();

    // wait for all threads in the thread pool to complete
    void wait();

    // placeholder for a general approach to getting executors from 
    // standard contexts.
    executor_type executor() noexcept;
};

bool operator==(const static_thread_pool&amp; a, const static_thread_pool&amp; b) noexcept;
bool operator!=(const static_thread_pool&amp; a, const static_thread_pool&amp; b) noexcept;</code></pre>
<p>The class <code>static_thread_pool</code> satisfies the <code>ExecutionContext</code> requirements.</p>
<p>For an object of type <code>static_thread_pool</code>, <em>outstanding work</em> is defined as the sum of:</p>
<ul>
<li><p>the number of existing executor objects associated with the <code>static_thread_pool</code> for which the <code>execution::outstanding_work</code> property is established;</p></li>
<li><p>the number of function objects that have been added to the <code>static_thread_pool</code> via the <code>static_thread_pool</code> executor, but not yet executed; and</p></li>
<li><p>the number of function objects that are currently being executed by the <code>static_thread_pool</code>.</p></li>
</ul>
<p>The <code>static_thread_pool</code> member functions <code>executor</code>, <code>attach</code>, <code>wait</code>, and <code>stop</code>, and the associated executors' copy constructors and member functions, do not introduce data races as a result of concurrent calls to those functions from different threads of execution.</p>
<h4 id="types"><span class="header-section-number">1.7.2.1</span> Types</h4>
<pre><code>using executor_type = see-below;</code></pre>
<p>An executor type conforming to the specification for <code>static_thread_pool</code> executor types described below.</p>
<h4 id="construction-and-destruction"><span class="header-section-number">1.7.2.2</span> Construction and destruction</h4>
<pre><code>static_thread_pool(std::size_t num_threads);</code></pre>
<p><em>Effects:</em> Constructs a <code>static_thread_pool</code> object with <code>num_threads</code> threads of execution, as if by creating objects of type <code>std::thread</code>.</p>
<pre><code>~static_thread_pool();</code></pre>
<p><em>Effects:</em> Destroys an object of class <code>static_thread_pool</code>. Performs <code>stop()</code> followed by <code>wait()</code>.</p>
<h4 id="worker-management"><span class="header-section-number">1.7.2.3</span> Worker management</h4>
<pre><code>void attach();</code></pre>
<p><em>Effects:</em> Adds the calling thread to the pool such that this thread is used to execute submitted function objects. [<em>Note:</em> Threads created during thread pool construction, or previously attached to the pool, will continue to be used for function object execution. <em>--end note</em>] Blocks the calling thread until signalled to complete by <code>stop()</code> or <code>wait()</code>, and then blocks until all the threads created during <code>static_thread_pool</code> object construction have completed. (NAMING: a possible alternate name for this function is <code>join()</code>.)</p>
<pre><code>void stop();</code></pre>
<p><em>Effects:</em> Signals the threads in the pool to complete as soon as possible. If a thread is currently executing a function object, the thread will exit only after completion of that function object. The call to <code>stop()</code> returns without waiting for the threads to complete. Subsequent calls to attach complete immediately.</p>
<pre><code>void wait();</code></pre>
<p><em>Effects:</em> If not already stopped, signals the threads in the pool to complete once the outstanding work is <code>0</code>. Blocks the calling thread (C++Std [defns.block]) until all threads in the pool have completed, without executing submitted function objects in the calling thread. Subsequent calls to attach complete immediately.</p>
<p><em>Synchronization:</em> The completion of each thread in the pool synchronizes with (C++Std [intro.multithread]) the corresponding successful <code>wait()</code> return.</p>
<h4 id="executor-creation"><span class="header-section-number">1.7.2.4</span> Executor creation</h4>
<pre><code>executor_type executor() noexcept;</code></pre>
<p><em>Returns:</em> An executor that may be used to submit function objects to the thread pool. The returned executor has the following properties already established:</p>
<ul>
<li><code>execution::oneway</code></li>
<li><code>execution::twoway</code></li>
<li><code>execution::then</code></li>
<li><code>execution::single</code></li>
<li><code>execution::bulk</code></li>
<li><code>execution::possibly_blocking</code></li>
<li><code>execution::not_continuation</code></li>
<li><code>execution::not_outstanding_work</code></li>
<li><code>execution::caller_parallel_execution</code></li>
<li><code>execution::allocator(std::allocator&lt;void&gt;())</code></li>
</ul>
<h4 id="comparisons"><span class="header-section-number">1.7.2.5</span> Comparisons</h4>
<pre><code>bool operator==(const static_thread_pool&amp; a, const static_thread_pool&amp; b) noexcept;</code></pre>
<p><em>Returns:</em> <code>std::addressof(a) == std::addressof(b)</code>.</p>
<pre><code>bool operator!=(const static_thread_pool&amp; a, const static_thread_pool&amp; b) noexcept;</code></pre>
<p><em>Returns:</em> <code>!(a == b)</code>.</p>
<h3 id="static_thread_pool-executor-types"><span class="header-section-number">1.7.3</span> <code>static_thread_pool</code> executor types</h3>
<p>All executor types accessible through <code>static_thread_pool::executor()</code>, and subsequent calls to the member function <code>require</code>, conform to the following specification.</p>
<pre><code>class C
{
  public:
    // types:

    typedef std::size_t shape_type;
    typedef std::size_t index_type;

    // construct / copy / destroy:

    C(const C&amp; other) noexcept;
    C(C&amp;&amp; other) noexcept;

    C&amp; operator=(const C&amp; other) noexcept;
    C&amp; operator=(C&amp;&amp; other) noexcept;

    // executor operations:

    C require(execution::oneway_t) const;
    C require(execution::twoway_t) const;
    C require(execution::then_t) const;
    C require(execution::single_t) const;
    C require(execution::bulk_t) const;
    C require(execution::caller_parallel_execution_t) const;
    C require(execution::bulk_parallel_execution_t) const;
    C require(execution::thread_execution_mapping_t) const;
    see-below require(execution::never_blocking_t) const;
    see-below require(execution::possibly_blocking_t) const;
    see-below require(execution::always_blocking_t) const;
    see-below require(execution::continuation_t) const;
    see-below require(execution::not_continuation_t) const;
    see-below require(execution::outstanding_work_t) const;
    see-below require(execution::not_outstanding_work_t) const;
    template&lt;class ProtoAllocator&gt;
      see-below require(const execution::allocator_wrapper_t&lt;ProtoAllocator&gt;&amp; a) const;

    bool running_in_this_thread() const noexcept;

    static_thread_pool&amp; context() const noexcept;

    template&lt;class Function&gt;
      void execute(Function&amp;&amp; f) const;

    template&lt;class Function&gt;
      std::experimental::future&lt;result_of_t&lt;decay_t&lt;Function&gt;()&gt;&gt;
        twoway_execute(Function&amp;&amp; f) const

    template&lt;class Function, class Future&gt;
      std::experimental::future&lt;result_of_t&lt;decay_t&lt;Function&gt;(decay_t&lt;Future&gt;)&gt;&gt;
        then_execute(Function&amp;&amp; f, Future&amp;&amp; pred) const;

    template&lt;class Function, class SharedFactory&gt;
      void bulk_execute(Function&amp;&amp; f, size_t n, SharedFactory&amp;&amp; sf) const;

    template&lt;class Function, class ResultFactory, class SharedFactory&gt;
      std::experimental::future&lt;result_of_t&lt;decay_t&lt;ResultFactory&gt;()&gt;&gt;
        void bulk_twoway_execute(Function&amp;&amp; f, size_t n, ResultFactory&amp;&amp; rf, SharedFactory&amp;&amp; sf) const;
};

bool operator==(const C&amp; a, const C&amp; b) noexcept;
bool operator!=(const C&amp; a, const C&amp; b) noexcept;</code></pre>
<p><code>C</code> is a type satisfying the <code>BaseExecutor</code>, <code>OneWayExecutor</code>, <code>TwoWayExecutor</code>, <code>BulkOneWayExecutor</code>, and <code>BulkTwoWayExecutor</code> requirements. Objects of type <code>C</code> are associated with a <code>static_thread_pool</code>.</p>
<h4 id="constructors"><span class="header-section-number">1.7.3.1</span> Constructors</h4>
<pre><code>C(const C&amp; other) noexcept;</code></pre>
<p><em>Postconditions:</em> <code>*this == other</code>.</p>
<pre><code>C(C&amp;&amp; other) noexcept;</code></pre>
<p><em>Postconditions:</em> <code>*this</code> is equal to the prior value of <code>other</code>.</p>
<h4 id="assignment"><span class="header-section-number">1.7.3.2</span> Assignment</h4>
<pre><code>C&amp; operator=(const C&amp; other) noexcept;</code></pre>
<p><em>Postconditions:</em> <code>*this == other</code>.</p>
<p><em>Returns:</em> <code>*this</code>.</p>
<pre><code>C&amp; operator=(C&amp;&amp; other) noexcept;</code></pre>
<p><em>Postconditions:</em> <code>*this</code> is equal to the prior value of <code>other</code>.</p>
<p><em>Returns:</em> <code>*this</code>.</p>
<h4 id="operations"><span class="header-section-number">1.7.3.3</span> Operations</h4>
<pre><code>C require(execution::oneway_t) const;
C require(execution::twoway_t) const;
C require(execution::then_t) const;
C require(execution::single_t) const;
C require(execution::bulk_t) const;
C require(execution::caller_parallel_execution_t) const;
C require(execution::bulk_parallel_execution_t) const;
C require(execution::thread_execution_mapping_t) const;</code></pre>
<p><em>Returns:</em> <code>*this</code>.</p>
<pre><code>see-below require(execution::never_blocking_t) const;
see-below require(execution::possibly_blocking_t) const;
see-below require(execution::always_blocking_t) const;
see-below require(execution::continuation_t) const;
see-below require(execution::not_continuation_t) const;
see-below require(execution::outstanding_work_t) const;
see-below require(execution::not_outstanding_work_t) const;</code></pre>
<p><em>Returns:</em> An executor object of an unspecified type conforming to these specifications, associated with the same thread pool as <code>*this</code>, and having the requested property established. When the requested property is part of a group that is defined as a mutually exclusive set, any other properties in the group are removed from the returned executor object. All other properties of the returned executor object are identical to those of <code>*this</code>.</p>
<pre><code>template&lt;class ProtoAllocator&gt;
  see-below require(const execution::allocator_wrapper_t&lt;ProtoAllocator&gt;&amp; a) const;</code></pre>
<p><em>Returns:</em> An executor object of an unspecified type conforming to these specifications, associated with the same thread pool as <code>*this</code>, with the <code>execution::allocator_wrapper_t&lt;ProtoAllocator&gt;</code> property established such that allocation and deallocation associated with function submission will be performed using a copy of <code>a.alloc</code>. All other properties of the returned executor object are identical to those of <code>*this</code>.</p>
<pre><code>bool running_in_this_thread() const noexcept;</code></pre>
<p><em>Returns:</em> <code>true</code> if the current thread of execution is a thread that was created by or attached to the associated <code>static_thread_pool</code> object.</p>
<pre><code>static_thread_pool&amp; context() const noexcept;</code></pre>
<p><em>Returns:</em> A reference to the associated <code>static_thread_pool</code> object.</p>
<pre><code>template&lt;class Function&gt;
  void execute(Function&amp;&amp; f) const;</code></pre>
<p><em>Effects:</em> Submits the function <code>f</code> for execution on the <code>static_thread_pool</code> according to the <code>OneWayExecutor</code> requirements and the properties established for <code>*this</code>. If the submitted function <code>f</code> exits via an exception, the <code>static_thread_pool</code> calls <code>std::terminate()</code>.</p>
<pre><code>template&lt;class Function&gt;
  std::experimental::future&lt;result_of_t&lt;decay_t&lt;Function&gt;()&gt;&gt;
    twoway_execute(Function&amp;&amp; f) const</code></pre>
<p><em>Effects:</em> Submits the function <code>f</code> for execution on the <code>static_thread_pool</code> according to the <code>TwoWayExecutor</code> requirements and the properties established for <code>*this</code>.</p>
<p><em>Returns:</em> A future with behavior as specified by the <code>TwoWayExecutor</code> requirements.</p>
<pre><code>template&lt;class Function, class Future&gt;
  std::experimental::future&lt;result_of_t&lt;decay_t&lt;Function&gt;(decay_t&lt;Future&gt;)&gt;&gt;
    then_execute(Function&amp;&amp; f, Future&amp;&amp; pred) const</code></pre>
<p><em>Effects:</em> Submits the function <code>f</code> for execution on the <code>static_thread_pool</code> according to the <code>ThenExecutor</code> requirements and the properties established for <code>*this</code>.</p>
<p><em>Returns:</em> A future with behavior as specified by the <code>ThenExecutor</code> requirements.</p>
<pre><code>template&lt;class Function, class SharedFactory&gt;
  void bulk_execute(Function&amp;&amp; f, size_t n, SharedFactory&amp;&amp; sf) const;</code></pre>
<p><em>Effects:</em> Submits the function <code>f</code> for bulk execution on the <code>static_thread_pool</code> according to the <code>BulkOneWayExecutor</code> requirements and the properties established for <code>*this</code>. If the submitted function <code>f</code> exits via an exception, the <code>static_thread_pool</code> calls <code>std::terminate()</code>.</p>
<pre><code>template&lt;class Function, class ResultFactory, class SharedFactory&gt;
  std::experimental::future&lt;result_of_t&lt;decay_t&lt;ResultFactory&gt;()&gt;&gt;
    void bulk_twoway_execute(Function&amp;&amp; f, size_t n, ResultFactory&amp;&amp; rf, SharedFactory&amp;&amp; sf) const;</code></pre>
<p><em>Effects:</em> Submits the function <code>f</code> for bulk execution on the <code>static_thread_pool</code> according to the <code>BulkTwoWayExecutor</code> requirements and the properties established for <code>*this</code>.</p>
<p><em>Returns:</em> A future with behavior as specified by the <code>BulkTwoWayExecutor</code> requirements.</p>
<pre><code>template&lt;class Function, class Future, class ResultFactory, class SharedFactory&gt;
  std::experimental::future&lt;result_of_t&lt;decay_t&lt;ResultFactory&gt;()&gt;&gt;
    void bulk_then_execute(Function&amp;&amp; f, size_t n, Future&amp;&amp; pred, ResultFactory&amp;&amp; rf, SharedFactory&amp;&amp; sf) const;</code></pre>
<p><em>Effects:</em> Submits the function <code>f</code> for bulk execution on the <code>static_thread_pool</code> according to the <code>BulkThenExecutor</code> requirements and the properties established for <code>*this</code>.</p>
<p><em>Returns:</em> A future with behavior as specified by the <code>BulkThenExecutor</code> requirements.</p>
<h4 id="comparisons-1"><span class="header-section-number">1.7.3.4</span> Comparisons</h4>
<pre><code>bool operator==(const C&amp; a, const C&amp; b) noexcept;</code></pre>
<p><em>Returns:</em> <code>true</code> if <code>a.context() == b.context()</code> and <code>a</code> and <code>b</code> have identical properties, otherwise <code>false</code>.</p>
<pre><code>bool operator!=(const C&amp; a, const C&amp; b) noexcept;</code></pre>
<p><em>Returns:</em> <code>!(a == b)</code>.</p>
