diff --git a/include/boost/asio/defer.hpp b/include/boost/asio/defer.hpp
index d51a5877..8bf0477a 100644
--- a/include/boost/asio/defer.hpp
+++ b/include/boost/asio/defer.hpp
@@ -59,10 +59,11 @@ namespace asio {
* The function call operator of @c Init:
*
* @li Obtains the handler's associated executor object @c ex of type @c Ex by
- * performing @code auto ex = get_associated_executor(handler); @endcode
+ * performing
+ * @code auto ex = get_associated_executor(completion_handler); @endcode
*
* @li Obtains the handler's associated allocator object @c alloc by performing
- * @code auto alloc = get_associated_allocator(handler); @endcode
+ * @code auto alloc = get_associated_allocator(completion_handler); @endcode
*
* @li If execution::is_executor::value is true, performs
* @code prefer(
@@ -80,7 +81,7 @@ namespace asio {
* @code void() @endcode
*/
template
-auto defer(NullaryToken&& token)
+inline auto defer(NullaryToken&& token)
-> decltype(
async_initiate(
declval(), token))
@@ -125,10 +126,11 @@ auto defer(NullaryToken&& token)
* The function call operator of @c Init:
*
* @li Obtains the handler's associated executor object @c ex1 of type @c Ex1 by
- * performing @code auto ex1 = get_associated_executor(handler, ex); @endcode
+ * performing
+ * @code auto ex1 = get_associated_executor(completion_handler, ex); @endcode
*
* @li Obtains the handler's associated allocator object @c alloc by performing
- * @code auto alloc = get_associated_allocator(handler); @endcode
+ * @code auto alloc = get_associated_allocator(completion_handler); @endcode
*
* @li If execution::is_executor::value is true, constructs a
* function object @c f with a member @c executor_ that is initialised with
@@ -147,14 +149,14 @@ auto defer(NullaryToken&& token)
* work_.get_executor().dispatch(std::move(handler_), a);
* work_.reset(); @endcode
*
- * @li If execution::is_executor::value is true, performs
+ * @li If execution::is_executor::value is true, performs
* @code prefer(
* require(ex, execution::blocking.never),
* execution::relationship.continuation,
* execution::allocator(alloc)
* ).execute(std::move(f)); @endcode
*
- * @li If execution::is_executor::value is false, performs
+ * @li If execution::is_executor::value is false, performs
* @code ex.defer(std::move(f), alloc); @endcode
*
* @par Completion Signature
@@ -163,9 +165,8 @@ auto defer(NullaryToken&& token)
template >
-auto defer(const Executor& ex,
- NullaryToken&& token
- = default_completion_token_t(),
+inline auto defer(const Executor& ex,
+ NullaryToken&& token = default_completion_token_t(),
constraint_t<
(execution::is_executor::value
&& can_require::value)
@@ -173,10 +174,12 @@ auto defer(const Executor& ex,
> = 0)
-> decltype(
async_initiate(
- declval>(), token))
+ declval>(),
+ token, detail::empty_work_function()))
{
return async_initiate(
- detail::initiate_defer_with_executor(ex), token);
+ detail::initiate_defer_with_executor(ex),
+ token, detail::empty_work_function());
}
/// Submits a completion token or function object for execution.
@@ -195,21 +198,343 @@ auto defer(const Executor& ex,
template >
-auto defer(ExecutionContext& ctx,
- NullaryToken&& token
- = default_completion_token_t(),
+inline auto defer(ExecutionContext& ctx,
+ NullaryToken&& token = default_completion_token_t<
+ typename ExecutionContext::executor_type>(),
constraint_t<
is_convertible::value
> = 0)
-> decltype(
async_initiate(
declval>(), token))
+ typename ExecutionContext::executor_type>>(),
+ token, detail::empty_work_function()))
{
return async_initiate(
detail::initiate_defer_with_executor<
- typename ExecutionContext::executor_type>(
- ctx.get_executor()), token);
+ typename ExecutionContext::executor_type>(ctx.get_executor()),
+ token, detail::empty_work_function());
+}
+
+
+/// Submits a function to be run on a specified target executor, and after
+/// completion submits the completion handler.
+/**
+ * This function submits a function object for execution on the specified
+ * executor. The function object is queued for execution, and is never called
+ * from the current thread prior to returning from defer(). After the
+ * submitted function completes, the completion handler is dispatched to run on
+ * its associated executor.
+ *
+ * The use of @c defer(), rather than @ref post(), indicates the caller's
+ * preference that the executor defer the queueing of the function object. This
+ * may allow the executor to optimise queueing for cases when the function
+ * object represents a continuation of the current call context.
+ *
+ * @param function A nullary function to be executed on the target executor.
+ *
+ * @param ex The target executor.
+ *
+ * @param token The @ref completion_token that will be used to produce a
+ * completion handler. The function signature of the completion handler must be:
+ * @code void handler(); @endcode
+ *
+ * @returns This function returns async_initiate(Init{ex}, token, forward(function)), where @c Init is
+ * a function object type defined as:
+ *
+ * @code class Init
+ * {
+ * public:
+ * using executor_type = Executor;
+ * explicit Init(const Executor& ex) : ex_(ex) {}
+ * executor_type get_executor() const noexcept { return ex_; }
+ * template
+ * void operator()(CompletionHandler&& completion_handler,
+ * Function&& function) const;
+ * private:
+ * Executor ex_; // exposition only
+ * }; @endcode
+ *
+ * The function call operator of @c Init:
+ *
+ * @li Obtains the handler's associated executor object @c ex1 of type @c Ex1 by
+ * performing
+ * @code auto ex1 = get_associated_executor(completion_handler, ex); @endcode
+ *
+ * @li Obtains the handler's associated allocator object @c alloc by performing
+ * @code auto alloc = get_associated_allocator(completion_handler); @endcode
+ *
+ * @li If execution::is_executor::value is true, constructs a
+ * function object wrapper @c f with a member @c executor_ that is initialised
+ * with prefer(ex1, execution::outstanding_work.tracked), a member @c
+ * function_ that is a decay-copy of @c function, a member @c handler_ that is a
+ * decay-copy of @c completion_handler, and a function call operator that
+ * performs:
+ * @code std::move(function_)();
+ * auto a = get_associated_allocator(handler_);
+ * prefer(executor_, execution::allocator(a)).execute(std::move(handler_));
+ * @endcode
+ *
+ * @li If execution::is_executor::value is false, constructs a
+ * function object wrapper @c f with a member @c work_ that is initialised with
+ * make_work_guard(ex1), a member @c function_ that is a decay-copy of
+ * @c function, a member @c handler_ that is a decay-copy of @c
+ * completion_handler, and a function call operator that performs:
+ * @code std::move(function_)();
+ * auto a = get_associated_allocator(handler_);
+ * work_.get_executor().dispatch(std::move(handler_), a);
+ * work_.reset(); @endcode
+ *
+ * @li If execution::is_executor::value is true, performs
+ * @code prefer(
+ * require(ex, execution::blocking.never),
+ * execution::relationship.fork,
+ * execution::allocator(alloc)
+ * ).execute(std::move(f)); @endcode
+ *
+ * @li If execution::is_executor::value is false, performs
+ * @code ex.defer(std::move(f), alloc); @endcode
+ *
+ * @note If the function object throws an exception, that exception is allowed
+ * to propagate to the target executor. The behaviour in this case is dependent
+ * on the executor. For example, boost::asio::io_context will allow the
+ * exception to propagate to the caller that runs the @c io_context, whereas
+ * boost::asio::thread_pool will call @c std::terminate.
+ *
+ * @par Completion Signature
+ * @code void() @endcode
+ */
+template >
+inline auto defer(Function&& function, const Executor& ex,
+ NullaryToken&& token = default_completion_token_t(),
+ constraint_t<
+ is_void()>>::value
+ > = 0,
+ constraint_t<
+ (execution::is_executor::value
+ && can_require::value)
+ || is_executor::value
+ > = 0)
+ -> decltype(
+ async_initiate(
+ declval>(),
+ token, static_cast(function)))
+{
+ return async_initiate(
+ detail::initiate_defer_with_executor(ex),
+ token, static_cast(function));
+}
+
+/// Submits a function to be run on a specified target executor, and passes the
+/// result to a completion handler.
+/**
+ * This function submits a function object for execution on the specified
+ * executor. The function object is queued for execution, and is never called
+ * from the current thread prior to returning from defer(). After the
+ * submitted function completes, the completion handler is dispatched along with
+ * the function's result, to run on its associated executor.
+ *
+ * The use of @c defer(), rather than @ref post(), indicates the caller's
+ * preference that the executor defer the queueing of the function object. This
+ * may allow the executor to optimise queueing for cases when the function
+ * object represents a continuation of the current call context.
+ *
+ * @param function A nullary function to be executed on the target executor.
+ *
+ * @param ex The target executor.
+ *
+ * @param token The @ref completion_token that will be used to produce a
+ * completion handler. The function signature of the completion handler must be:
+ * @code void handler(decay_t()>>); @endcode
+ *
+ * @returns This function returns async_initiate(Init{ex}, token), where @c Init is a function object type
+ * defined as:
+ *
+ * @code class Init
+ * {
+ * public:
+ * using executor_type = Executor;
+ * explicit Init(const Executor& ex) : ex_(ex) {}
+ * executor_type get_executor() const noexcept { return ex_; }
+ * template
+ * void operator()(CompletionHandler&& completion_handler,
+ * Function&& function) const;
+ * private:
+ * Executor ex_; // exposition only
+ * }; @endcode
+ *
+ * The function call operator of @c Init:
+ *
+ * @li Obtains the handler's associated executor object @c ex1 of type @c Ex1 by
+ * performing
+ * @code auto ex1 = get_associated_executor(completion_handler, ex); @endcode
+ *
+ * @li Obtains the handler's associated allocator object @c alloc by performing
+ * @code auto alloc = get_associated_allocator(completion_handler); @endcode
+ *
+ * @li If execution::is_executor::value is true, constructs a
+ * function object wrapper @c f with a member @c executor_ that is initialised
+ * with prefer(ex1, execution::outstanding_work.tracked), a member @c
+ * function_ that is a decay-copy of @c function, a member @c handler_ that is a
+ * decay-copy of @c completion_handler, and a function call operator that
+ * performs:
+ * @code auto result = std::move(function_)();
+ * auto a = get_associated_allocator(handler_);
+ * prefer(executor_, execution::allocator(a)).execute(
+ * std::bind(std::move(handler_), std::move(result)));
+ * @endcode
+ *
+ * @li If execution::is_executor::value is false, constructs a
+ * function object wrapper @c f with a member @c work_ that is initialised with
+ * make_work_guard(ex1), a member @c function_ that is a decay-copy of
+ * @c function, a member @c handler_ that is a decay-copy of @c
+ * completion_handler, and a function call operator that performs:
+ * @code auto result = std::move(function_)();
+ * auto a = get_associated_allocator(handler_);
+ * work_.get_executor().dispatch(
+ * std::bind(std::move(handler_), std::move(result)), a);
+ * work_.reset(); @endcode
+ *
+ * @li If execution::is_executor::value is true, performs
+ * @code prefer(
+ * require(ex, execution::blocking.never),
+ * execution::relationship.fork,
+ * execution::allocator(alloc)
+ * ).execute(std::move(f)); @endcode
+ *
+ * @li If execution::is_executor::value is false, performs
+ * @code ex.defer(std::move(f), alloc); @endcode
+ *
+ * @note If the function object throws an exception, that exception is allowed
+ * to propagate to the target executor. The behaviour in this case is dependent
+ * on the executor. For example, boost::asio::io_context will allow the
+ * exception to propagate to the caller that runs the @c io_context, whereas
+ * boost::asio::thread_pool will call @c std::terminate.
+ *
+ * @par Completion Signature
+ * @code void(decay_t()>>) @endcode
+ */
+template ()>>)) CompletionToken
+ = default_completion_token_t>
+inline auto defer(Function&& function, const Executor& ex,
+ CompletionToken&& token = default_completion_token_t(),
+ constraint_t<
+ !is_void()>>::value
+ > = 0,
+ constraint_t<
+ (execution::is_executor::value
+ && can_require::value)
+ || is_executor::value
+ > = 0)
+ -> decltype(
+ async_initiate)>(
+ declval>(),
+ token, static_cast(function)))
+{
+ return async_initiate)>(
+ detail::initiate_defer_with_executor(ex),
+ token, static_cast(function));
+}
+
+/// Submits a function to be run on a specified execution context, and after
+/// completion submits the completion handler.
+/**
+ * @param function A nullary function to be executed on the target executor.
+ *
+ * @param ctx An execution context, from which the target executor is obtained.
+ *
+ * @param token The @ref completion_token that will be used to produce a
+ * completion handler. The function signature of the completion handler must be:
+ * @code void handler(); @endcode
+ *
+ * @returns defer(forward(function), ctx.get_executor(),
+ * forward(token)).
+ *
+ * @note If the function object throws an exception, that exception is allowed
+ * to propagate to the target executor. The behaviour in this case is dependent
+ * on the executor. For example, boost::asio::io_context will allow the
+ * exception to propagate to the caller that runs the @c io_context, whereas
+ * boost::asio::thread_pool will call @c std::terminate.
+ *
+ * @par Completion Signature
+ * @code void() @endcode
+ */
+template >
+inline auto defer(Function&& function, ExecutionContext& ctx,
+ NullaryToken&& token = default_completion_token_t<
+ typename ExecutionContext::executor_type>(),
+ constraint_t<
+ is_void()>>::value
+ > = 0,
+ constraint_t<
+ is_convertible::value
+ > = 0)
+ -> decltype(
+ async_initiate(
+ declval>(),
+ token, static_cast(function)))
+{
+ return async_initiate(
+ detail::initiate_defer_with_executor<
+ typename ExecutionContext::executor_type>(ctx.get_executor()),
+ token, static_cast(function));
+}
+
+/// Submits a function to be run on a specified execution context, and passes
+/// the result to a completion handler.
+/**
+ * @param function A nullary function to be executed on the target executor.
+ *
+ * @param ctx An execution context, from which the target executor is obtained.
+ *
+ * @param token The @ref completion_token that will be used to produce a
+ * completion handler. The function signature of the completion handler must be:
+ * @code void handler(); @endcode
+ *
+ * @returns defer(forward(function), ctx.get_executor(),
+ * forward(token)).
+ *
+ * @note If the function object throws an exception, that exception is allowed
+ * to propagate to the target executor. The behaviour in this case is dependent
+ * on the executor. For example, boost::asio::io_context will allow the
+ * exception to propagate to the caller that runs the @c io_context, whereas
+ * boost::asio::thread_pool will call @c std::terminate.
+ *
+ * @par Completion Signature
+ * @code void(decay_t()>>) @endcode
+ */
+template ()>>)) CompletionToken
+ = default_completion_token_t>
+inline auto defer(Function&& function, ExecutionContext& ctx,
+ CompletionToken&& token = default_completion_token_t<
+ typename ExecutionContext::executor_type>(),
+ constraint_t<
+ !is_void()>>::value
+ > = 0,
+ constraint_t<
+ is_convertible::value
+ > = 0)
+ -> decltype(
+ async_initiate)>(
+ declval>(),
+ token, static_cast(function)))
+{
+ return async_initiate)>(
+ detail::initiate_defer_with_executor<
+ typename ExecutionContext::executor_type>(ctx.get_executor()),
+ token, static_cast(function));
}
} // namespace asio
diff --git a/include/boost/asio/detail/bind_handler.hpp b/include/boost/asio/detail/bind_handler.hpp
index df03387f..03cce347 100644
--- a/include/boost/asio/detail/bind_handler.hpp
+++ b/include/boost/asio/detail/bind_handler.hpp
@@ -490,6 +490,14 @@ public:
Arg1 arg1_;
};
+template
+inline move_binder1, decay_t> move_bind_handler(
+ Handler&& handler, Arg1&& arg1)
+{
+ return move_binder1, decay_t>(0,
+ static_cast(handler), static_cast(arg1));
+}
+
template
inline bool asio_handler_is_continuation(
move_binder1* this_handler)
diff --git a/include/boost/asio/detail/handler_work.hpp b/include/boost/asio/detail/handler_work.hpp
index ff6fb7b4..80b3770b 100644
--- a/include/boost/asio/detail/handler_work.hpp
+++ b/include/boost/asio/detail/handler_work.hpp
@@ -497,7 +497,7 @@ public:
handler, *static_cast(io_ex));
(initiate_dispatch_with_executor(immediate_ex))(
- static_cast(function));
+ static_cast(function), empty_work_function());
}
private:
diff --git a/include/boost/asio/detail/initiate_defer.hpp b/include/boost/asio/detail/initiate_defer.hpp
index e3336238..3da0a6da 100644
--- a/include/boost/asio/detail/initiate_defer.hpp
+++ b/include/boost/asio/detail/initiate_defer.hpp
@@ -92,15 +92,16 @@ public:
return ex_;
}
- template
- void operator()(CompletionHandler&& handler,
+ template
+ void operator()(CompletionHandler&& handler, Function&&,
enable_if_t<
execution::is_executor<
conditional_t
>::value
>* = 0,
enable_if_t<
- !detail::is_work_dispatcher_required<
+ !is_work_dispatcher_required<
+ decay_t,
decay_t,
Executor
>::value
@@ -118,21 +119,23 @@ public:
static_cast(handler)));
}
- template
- void operator()(CompletionHandler&& handler,
+ template
+ void operator()(CompletionHandler&& handler, Function&& function,
enable_if_t<
execution::is_executor<
conditional_t
>::value
>* = 0,
enable_if_t<
- detail::is_work_dispatcher_required<
+ is_work_dispatcher_required<
+ decay_t,
decay_t,
Executor
>::value
>* = 0) const
{
typedef decay_t handler_t;
+ typedef decay_t function_t;
typedef associated_executor_t handler_ex_t;
handler_ex_t handler_ex((get_associated_executor)(handler, ex_));
@@ -145,19 +148,21 @@ public:
execution::relationship.continuation,
execution::allocator(alloc)
).execute(
- detail::work_dispatcher(
+ work_dispatcher(
+ static_cast(function),
static_cast(handler), handler_ex));
}
- template
- void operator()(CompletionHandler&& handler,
+ template
+ void operator()(CompletionHandler&& handler, Function&&,
enable_if_t<
!execution::is_executor<
conditional_t
>::value
>* = 0,
enable_if_t<
- !detail::is_work_dispatcher_required<
+ !is_work_dispatcher_required<
+ decay_t,
decay_t,
Executor
>::value
@@ -170,21 +175,23 @@ public:
static_cast(handler)), alloc);
}
- template
- void operator()(CompletionHandler&& handler,
+ template
+ void operator()(CompletionHandler&& handler, Function&& function,
enable_if_t<
!execution::is_executor<
conditional_t
>::value
>* = 0,
enable_if_t<
- detail::is_work_dispatcher_required<
+ is_work_dispatcher_required<
+ decay_t,
decay_t,
Executor
>::value
>* = 0) const
{
typedef decay_t handler_t;
+ typedef decay_t function_t;
typedef associated_executor_t handler_ex_t;
handler_ex_t handler_ex((get_associated_executor)(handler, ex_));
@@ -192,7 +199,8 @@ public:
associated_allocator_t alloc(
(get_associated_allocator)(handler));
- ex_.defer(detail::work_dispatcher(
+ ex_.defer(work_dispatcher(
+ static_cast(function),
static_cast(handler), handler_ex), alloc);
}
diff --git a/include/boost/asio/detail/initiate_dispatch.hpp b/include/boost/asio/detail/initiate_dispatch.hpp
index aaaa165b..d4cf2dfc 100644
--- a/include/boost/asio/detail/initiate_dispatch.hpp
+++ b/include/boost/asio/detail/initiate_dispatch.hpp
@@ -86,15 +86,16 @@ public:
return ex_;
}
- template
- void operator()(CompletionHandler&& handler,
+ template
+ void operator()(CompletionHandler&& handler, Function&&,
enable_if_t<
execution::is_executor<
conditional_t
>::value
>* = 0,
enable_if_t<
- !detail::is_work_dispatcher_required<
+ !is_work_dispatcher_required<
+ decay_t,
decay_t,
Executor
>::value
@@ -108,21 +109,23 @@ public:
static_cast(handler)));
}
- template
- void operator()(CompletionHandler&& handler,
+ template
+ void operator()(CompletionHandler&& handler, Function&& function,
enable_if_t<
execution::is_executor<
conditional_t
>::value
>* = 0,
enable_if_t<
- detail::is_work_dispatcher_required<
+ is_work_dispatcher_required<
+ decay_t,
decay_t,
Executor
>::value
>* = 0) const
{
typedef decay_t handler_t;
+ typedef decay_t function_t;
typedef associated_executor_t handler_ex_t;
handler_ex_t handler_ex((get_associated_executor)(handler, ex_));
@@ -131,19 +134,21 @@ public:
(get_associated_allocator)(handler));
boost::asio::prefer(ex_, execution::allocator(alloc)).execute(
- detail::work_dispatcher(
+ work_dispatcher(
+ static_cast(function),
static_cast(handler), handler_ex));
}
- template
- void operator()(CompletionHandler&& handler,
+ template
+ void operator()(CompletionHandler&& handler, Function&&,
enable_if_t<
!execution::is_executor<
conditional_t
>::value
>* = 0,
enable_if_t<
- !detail::is_work_dispatcher_required<
+ !is_work_dispatcher_required<
+ decay_t,
decay_t,
Executor
>::value
@@ -156,21 +161,23 @@ public:
static_cast(handler)), alloc);
}
- template
- void operator()(CompletionHandler&& handler,
+ template
+ void operator()(CompletionHandler&& handler, Function&& function,
enable_if_t<
!execution::is_executor<
conditional_t
>::value
>* = 0,
enable_if_t<
- detail::is_work_dispatcher_required<
+ is_work_dispatcher_required<
+ decay_t,
decay_t,
Executor
>::value
>* = 0) const
{
typedef decay_t handler_t;
+ typedef decay_t function_t;
typedef associated_executor_t handler_ex_t;
handler_ex_t handler_ex((get_associated_executor)(handler, ex_));
@@ -178,7 +185,8 @@ public:
associated_allocator_t alloc(
(get_associated_allocator)(handler));
- ex_.dispatch(detail::work_dispatcher(
+ ex_.dispatch(work_dispatcher(
+ static_cast(function),
static_cast(handler), handler_ex), alloc);
}
diff --git a/include/boost/asio/detail/initiate_post.hpp b/include/boost/asio/detail/initiate_post.hpp
index a7adb1f6..0e140fbb 100644
--- a/include/boost/asio/detail/initiate_post.hpp
+++ b/include/boost/asio/detail/initiate_post.hpp
@@ -92,15 +92,16 @@ public:
return ex_;
}
- template
- void operator()(CompletionHandler&& handler,
+ template
+ void operator()(CompletionHandler&& handler, Function&&,
enable_if_t<
execution::is_executor<
conditional_t
>::value
>* = 0,
enable_if_t<
- !detail::is_work_dispatcher_required<
+ !is_work_dispatcher_required<
+ decay_t,
decay_t,
Executor
>::value
@@ -118,21 +119,23 @@ public:
static_cast(handler)));
}
- template
- void operator()(CompletionHandler&& handler,
+ template
+ void operator()(CompletionHandler&& handler, Function&& function,
enable_if_t<
execution::is_executor<
conditional_t
>::value
>* = 0,
enable_if_t<
- detail::is_work_dispatcher_required<
+ is_work_dispatcher_required<
+ decay_t,
decay_t,
Executor
>::value
>* = 0) const
{
typedef decay_t handler_t;
+ typedef decay_t function_t;
typedef associated_executor_t handler_ex_t;
handler_ex_t handler_ex((get_associated_executor)(handler, ex_));
@@ -145,19 +148,21 @@ public:
execution::relationship.fork,
execution::allocator(alloc)
).execute(
- detail::work_dispatcher(
+ work_dispatcher(
+ static_cast(function),
static_cast(handler), handler_ex));
}
- template
- void operator()(CompletionHandler&& handler,
+ template
+ void operator()(CompletionHandler&& handler, Function&&,
enable_if_t<
!execution::is_executor<
conditional_t
>::value
>* = 0,
enable_if_t<
- !detail::is_work_dispatcher_required<
+ !is_work_dispatcher_required<
+ decay_t,
decay_t,
Executor
>::value
@@ -170,21 +175,23 @@ public:
static_cast(handler)), alloc);
}
- template
- void operator()(CompletionHandler&& handler,
+ template
+ void operator()(CompletionHandler&& handler, Function&& function,
enable_if_t<
!execution::is_executor<
conditional_t
>::value
>* = 0,
enable_if_t<
- detail::is_work_dispatcher_required<
+ is_work_dispatcher_required<
+ decay_t,
decay_t,
Executor
>::value
>* = 0) const
{
typedef decay_t handler_t;
+ typedef decay_t function_t;
typedef associated_executor_t handler_ex_t;
handler_ex_t handler_ex((get_associated_executor)(handler, ex_));
@@ -192,7 +199,8 @@ public:
associated_allocator_t alloc(
(get_associated_allocator)(handler));
- ex_.post(detail::work_dispatcher(
+ ex_.post(work_dispatcher(
+ static_cast(function),
static_cast(handler), handler_ex), alloc);
}
diff --git a/include/boost/asio/detail/type_traits.hpp b/include/boost/asio/detail/type_traits.hpp
index 14eefa42..a5e8b6c2 100644
--- a/include/boost/asio/detail/type_traits.hpp
+++ b/include/boost/asio/detail/type_traits.hpp
@@ -110,6 +110,8 @@ using std::is_scalar;
using std::is_unsigned;
+using std::is_void;
+
using std::remove_cv;
template
diff --git a/include/boost/asio/detail/work_dispatcher.hpp b/include/boost/asio/detail/work_dispatcher.hpp
index 06d54142..7b7f92a4 100644
--- a/include/boost/asio/detail/work_dispatcher.hpp
+++ b/include/boost/asio/detail/work_dispatcher.hpp
@@ -33,13 +33,30 @@ namespace boost {
namespace asio {
namespace detail {
-template
+struct empty_work_function
+{
+ void operator()() const noexcept
+ {
+ }
+};
+
+template
+struct work_result
+{
+ typedef decay_t()>> type;
+};
+
+template
+using work_result_t = typename work_result::type;
+
+template
struct is_work_dispatcher_required : true_type
{
};
template
-struct is_work_dispatcher_required
-class work_dispatcher
+template >::value,
+ bool IsClass = is_class::value>
+class work_dispatcher_function
+{
+ Function function_;
+
+public:
+ template
+ work_dispatcher_function(F&& function)
+ : function_(static_cast(function))
+ {
+ }
+
+ work_dispatcher_function(const work_dispatcher_function& other)
+ : function_(other.function_)
+ {
+ }
+
+ work_dispatcher_function(work_dispatcher_function&& other)
+ : function_(static_cast(other.function_))
+ {
+ }
+
+ template
+ auto bind_result(Handler&& handler)
+ -> decltype(
+ boost::asio::detail::move_bind_handler(
+ static_cast(handler),
+ static_cast(function_)()))
+ {
+ return boost::asio::detail::move_bind_handler(
+ static_cast(handler),
+ static_cast(function_)());
+ }
+};
+
+template
+class work_dispatcher_function : Function
{
public:
- template
- work_dispatcher(CompletionHandler&& handler,
+ template
+ work_dispatcher_function(F&& function)
+ : Function(static_cast(function))
+ {
+ }
+
+ work_dispatcher_function(const work_dispatcher_function& other)
+ : Function(static_cast(other))
+ {
+ }
+
+ work_dispatcher_function(work_dispatcher_function&& other)
+ : Function(static_cast(other))
+ {
+ }
+
+ template
+ auto bind_result(Handler&& handler)
+ -> decltype(
+ boost::asio::detail::move_bind_handler(
+ static_cast(handler),
+ static_cast(*static_cast(this))()))
+ {
+ return boost::asio::detail::move_bind_handler(
+ static_cast(handler),
+ static_cast(*static_cast(this))());
+ }
+};
+
+template
+class work_dispatcher_function
+{
+ Function function_;
+
+public:
+ template
+ work_dispatcher_function(F&& function)
+ : function_(static_cast(function))
+ {
+ }
+
+ work_dispatcher_function(const work_dispatcher_function& other)
+ : function_(other.function_)
+ {
+ }
+
+ work_dispatcher_function(work_dispatcher_function&& other)
+ : function_(static_cast(other.function_))
+ {
+ }
+
+ template
+ auto bind_result(Handler&& handler)
+ -> decltype(boost::asio::detail::bind_handler(
+ static_cast(handler)))
+ {
+ static_cast(function_)();
+ return boost::asio::detail::bind_handler(
+ static_cast(handler));
+ }
+};
+
+template
+class work_dispatcher_function : Function
+{
+public:
+ template
+ work_dispatcher_function(F&& function)
+ : Function(static_cast(function))
+ {
+ }
+
+ work_dispatcher_function(const work_dispatcher_function& other)
+ : Function(static_cast(other))
+ {
+ }
+
+ work_dispatcher_function(work_dispatcher_function&& other)
+ : Function(static_cast(other))
+ {
+ }
+
+ template
+ auto bind_result(Handler&& handler)
+ -> decltype(boost::asio::detail::bind_handler(
+ static_cast(handler)))
+ {
+ static_cast(*static_cast(this))();
+ return boost::asio::detail::bind_handler(
+ static_cast(handler));
+ }
+};
+
+template
+class work_dispatcher : work_dispatcher_function
+{
+public:
+ template
+ work_dispatcher(F&& function, CompletionHandler&& handler,
const Executor& handler_ex)
- : handler_(static_cast(handler)),
+ : work_dispatcher_function(static_cast(function)),
+ handler_(static_cast(handler)),
executor_(boost::asio::prefer(handler_ex,
execution::outstanding_work.tracked))
{
}
work_dispatcher(const work_dispatcher& other)
- : handler_(other.handler_),
+ : work_dispatcher_function(other),
+ handler_(other.handler_),
executor_(other.executor_)
{
}
work_dispatcher(work_dispatcher&& other)
- : handler_(static_cast(other.handler_)),
+ : work_dispatcher_function(
+ static_cast