5 // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
11 #ifndef BOOST_ASIO_BIND_EXECUTOR_HPP
12 #define BOOST_ASIO_BIND_EXECUTOR_HPP
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18 #include <boost/asio/detail/config.hpp>
19 #include <boost/asio/detail/type_traits.hpp>
20 #include <boost/asio/detail/variadic_templates.hpp>
21 #include <boost/asio/associated_executor.hpp>
22 #include <boost/asio/associated_allocator.hpp>
23 #include <boost/asio/async_result.hpp>
24 #include <boost/asio/execution_context.hpp>
25 #include <boost/asio/is_executor.hpp>
26 #include <boost/asio/uses_executor.hpp>
28 #include <boost/asio/detail/push_options.hpp>
35 struct executor_binder_check
40 // Helper to automatically define nested typedef result_type.
42 template <typename T, typename = void>
43 struct executor_binder_result_type
46 typedef void result_type_or_void;
50 struct executor_binder_result_type<T,
51 typename executor_binder_check<typename T::result_type>::type>
53 typedef typename T::result_type result_type;
55 typedef result_type result_type_or_void;
59 struct executor_binder_result_type<R(*)()>
61 typedef R result_type;
63 typedef result_type result_type_or_void;
67 struct executor_binder_result_type<R(&)()>
69 typedef R result_type;
71 typedef result_type result_type_or_void;
74 template <typename R, typename A1>
75 struct executor_binder_result_type<R(*)(A1)>
77 typedef R result_type;
79 typedef result_type result_type_or_void;
82 template <typename R, typename A1>
83 struct executor_binder_result_type<R(&)(A1)>
85 typedef R result_type;
87 typedef result_type result_type_or_void;
90 template <typename R, typename A1, typename A2>
91 struct executor_binder_result_type<R(*)(A1, A2)>
93 typedef R result_type;
95 typedef result_type result_type_or_void;
98 template <typename R, typename A1, typename A2>
99 struct executor_binder_result_type<R(&)(A1, A2)>
101 typedef R result_type;
103 typedef result_type result_type_or_void;
106 // Helper to automatically define nested typedef argument_type.
108 template <typename T, typename = void>
109 struct executor_binder_argument_type {};
111 template <typename T>
112 struct executor_binder_argument_type<T,
113 typename executor_binder_check<typename T::argument_type>::type>
115 typedef typename T::argument_type argument_type;
118 template <typename R, typename A1>
119 struct executor_binder_argument_type<R(*)(A1)>
121 typedef A1 argument_type;
124 template <typename R, typename A1>
125 struct executor_binder_argument_type<R(&)(A1)>
127 typedef A1 argument_type;
130 // Helper to automatically define nested typedefs first_argument_type and
131 // second_argument_type.
133 template <typename T, typename = void>
134 struct executor_binder_argument_types {};
136 template <typename T>
137 struct executor_binder_argument_types<T,
138 typename executor_binder_check<typename T::first_argument_type>::type>
140 typedef typename T::first_argument_type first_argument_type;
141 typedef typename T::second_argument_type second_argument_type;
144 template <typename R, typename A1, typename A2>
145 struct executor_binder_argument_type<R(*)(A1, A2)>
147 typedef A1 first_argument_type;
148 typedef A2 second_argument_type;
151 template <typename R, typename A1, typename A2>
152 struct executor_binder_argument_type<R(&)(A1, A2)>
154 typedef A1 first_argument_type;
155 typedef A2 second_argument_type;
159 // - Apply the empty base optimisation to the executor.
160 // - Perform uses_executor construction of the target type, if required.
162 template <typename T, typename Executor, bool UsesExecutor>
163 class executor_binder_base;
165 template <typename T, typename Executor>
166 class executor_binder_base<T, Executor, true>
170 template <typename E, typename U>
171 executor_binder_base(BOOST_ASIO_MOVE_ARG(E) e, BOOST_ASIO_MOVE_ARG(U) u)
172 : executor_(BOOST_ASIO_MOVE_CAST(E)(e)),
173 target_(executor_arg_t(), executor_, BOOST_ASIO_MOVE_CAST(U)(u))
181 template <typename T, typename Executor>
182 class executor_binder_base<T, Executor, false>
185 template <typename E, typename U>
186 executor_binder_base(BOOST_ASIO_MOVE_ARG(E) e, BOOST_ASIO_MOVE_ARG(U) u)
187 : executor_(BOOST_ASIO_MOVE_CAST(E)(e)),
188 target_(BOOST_ASIO_MOVE_CAST(U)(u))
196 // Helper to enable SFINAE on zero-argument operator() below.
198 template <typename T, typename = void>
199 struct executor_binder_result_of0
204 template <typename T>
205 struct executor_binder_result_of0<T,
206 typename executor_binder_check<typename result_of<T()>::type>::type>
208 typedef typename result_of<T()>::type type;
211 } // namespace detail
213 /// A call wrapper type to bind an executor of type @c Executor to an object of
215 template <typename T, typename Executor>
216 class executor_binder
217 #if !defined(GENERATING_DOCUMENTATION)
218 : public detail::executor_binder_result_type<T>,
219 public detail::executor_binder_argument_type<T>,
220 public detail::executor_binder_argument_types<T>,
221 private detail::executor_binder_base<
222 T, Executor, uses_executor<T, Executor>::value>
223 #endif // !defined(GENERATING_DOCUMENTATION)
226 /// The type of the target object.
227 typedef T target_type;
229 /// The type of the associated executor.
230 typedef Executor executor_type;
232 #if defined(GENERATING_DOCUMENTATION)
233 /// The return type if a function.
235 * The type of @c result_type is based on the type @c T of the wrapper's
238 * @li if @c T is a pointer to function type, @c result_type is a synonym for
239 * the return type of @c T;
241 * @li if @c T is a class type with a member type @c result_type, then @c
242 * result_type is a synonym for @c T::result_type;
244 * @li otherwise @c result_type is not defined.
246 typedef see_below result_type;
248 /// The type of the function's argument.
250 * The type of @c argument_type is based on the type @c T of the wrapper's
253 * @li if @c T is a pointer to a function type accepting a single argument,
254 * @c argument_type is a synonym for the return type of @c T;
256 * @li if @c T is a class type with a member type @c argument_type, then @c
257 * argument_type is a synonym for @c T::argument_type;
259 * @li otherwise @c argument_type is not defined.
261 typedef see_below argument_type;
263 /// The type of the function's first argument.
265 * The type of @c first_argument_type is based on the type @c T of the
266 * wrapper's target object:
268 * @li if @c T is a pointer to a function type accepting two arguments, @c
269 * first_argument_type is a synonym for the return type of @c T;
271 * @li if @c T is a class type with a member type @c first_argument_type,
272 * then @c first_argument_type is a synonym for @c T::first_argument_type;
274 * @li otherwise @c first_argument_type is not defined.
276 typedef see_below first_argument_type;
278 /// The type of the function's second argument.
280 * The type of @c second_argument_type is based on the type @c T of the
281 * wrapper's target object:
283 * @li if @c T is a pointer to a function type accepting two arguments, @c
284 * second_argument_type is a synonym for the return type of @c T;
286 * @li if @c T is a class type with a member type @c first_argument_type,
287 * then @c second_argument_type is a synonym for @c T::second_argument_type;
289 * @li otherwise @c second_argument_type is not defined.
291 typedef see_below second_argument_type;
292 #endif // defined(GENERATING_DOCUMENTATION)
294 /// Construct an executor wrapper for the specified object.
296 * This constructor is only valid if the type @c T is constructible from type
299 template <typename U>
300 executor_binder(executor_arg_t, const executor_type& e,
301 BOOST_ASIO_MOVE_ARG(U) u)
302 : base_type(e, BOOST_ASIO_MOVE_CAST(U)(u))
306 /// Copy constructor.
307 executor_binder(const executor_binder& other)
308 : base_type(other.get_executor(), other.get())
312 /// Construct a copy, but specify a different executor.
313 executor_binder(executor_arg_t, const executor_type& e,
314 const executor_binder& other)
315 : base_type(e, other.get())
319 /// Construct a copy of a different executor wrapper type.
321 * This constructor is only valid if the @c Executor type is constructible
322 * from type @c OtherExecutor, and the type @c T is constructible from type
325 template <typename U, typename OtherExecutor>
326 executor_binder(const executor_binder<U, OtherExecutor>& other)
327 : base_type(other.get_executor(), other.get())
331 /// Construct a copy of a different executor wrapper type, but specify a
332 /// different executor.
334 * This constructor is only valid if the type @c T is constructible from type
337 template <typename U, typename OtherExecutor>
338 executor_binder(executor_arg_t, const executor_type& e,
339 const executor_binder<U, OtherExecutor>& other)
340 : base_type(e, other.get())
344 #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
346 /// Move constructor.
347 executor_binder(executor_binder&& other)
348 : base_type(BOOST_ASIO_MOVE_CAST(executor_type)(other.get_executor()),
349 BOOST_ASIO_MOVE_CAST(T)(other.get()))
353 /// Move construct the target object, but specify a different executor.
354 executor_binder(executor_arg_t, const executor_type& e,
355 executor_binder&& other)
356 : base_type(e, BOOST_ASIO_MOVE_CAST(T)(other.get()))
360 /// Move construct from a different executor wrapper type.
361 template <typename U, typename OtherExecutor>
362 executor_binder(executor_binder<U, OtherExecutor>&& other)
363 : base_type(BOOST_ASIO_MOVE_CAST(OtherExecutor)(other.get_executor()),
364 BOOST_ASIO_MOVE_CAST(U)(other.get()))
368 /// Move construct from a different executor wrapper type, but specify a
369 /// different executor.
370 template <typename U, typename OtherExecutor>
371 executor_binder(executor_arg_t, const executor_type& e,
372 executor_binder<U, OtherExecutor>&& other)
373 : base_type(e, BOOST_ASIO_MOVE_CAST(U)(other.get()))
377 #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
384 /// Obtain a reference to the target object.
385 target_type& get() BOOST_ASIO_NOEXCEPT
387 return this->target_;
390 /// Obtain a reference to the target object.
391 const target_type& get() const BOOST_ASIO_NOEXCEPT
393 return this->target_;
396 /// Obtain the associated executor.
397 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
399 return this->executor_;
402 #if defined(GENERATING_DOCUMENTATION)
404 template <typename... Args> auto operator()(Args&& ...);
405 template <typename... Args> auto operator()(Args&& ...) const;
407 #elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
409 /// Forwarding function call operator.
410 template <typename... Args>
411 typename result_of<T(Args...)>::type operator()(
412 BOOST_ASIO_MOVE_ARG(Args)... args)
414 return this->target_(BOOST_ASIO_MOVE_CAST(Args)(args)...);
417 /// Forwarding function call operator.
418 template <typename... Args>
419 typename result_of<T(Args...)>::type operator()(
420 BOOST_ASIO_MOVE_ARG(Args)... args) const
422 return this->target_(BOOST_ASIO_MOVE_CAST(Args)(args)...);
425 #elif defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER)
427 typename detail::executor_binder_result_of0<T>::type operator()()
429 return this->target_();
432 typename detail::executor_binder_result_of0<T>::type operator()() const
434 return this->target_();
437 #define BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF(n) \
438 template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \
439 typename result_of<T(BOOST_ASIO_VARIADIC_TARGS(n))>::type operator()( \
440 BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \
442 return this->target_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \
445 template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \
446 typename result_of<T(BOOST_ASIO_VARIADIC_TARGS(n))>::type operator()( \
447 BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) const \
449 return this->target_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \
452 BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF)
453 #undef BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF
455 #else // defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER)
457 typedef typename detail::executor_binder_result_type<T>::result_type_or_void
460 result_type_or_void operator()()
462 return this->target_();
465 result_type_or_void operator()() const
467 return this->target_();
470 #define BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF(n) \
471 template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \
472 result_type_or_void operator()( \
473 BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \
475 return this->target_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \
478 template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \
479 result_type_or_void operator()( \
480 BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) const \
482 return this->target_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \
485 BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF)
486 #undef BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF
488 #endif // defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER)
491 typedef detail::executor_binder_base<T, Executor,
492 uses_executor<T, Executor>::value> base_type;
495 /// Associate an object of type @c T with an executor of type @c Executor.
496 template <typename Executor, typename T>
497 inline executor_binder<typename decay<T>::type, Executor>
498 bind_executor(const Executor& ex, BOOST_ASIO_MOVE_ARG(T) t,
499 typename enable_if<is_executor<Executor>::value>::type* = 0)
501 return executor_binder<typename decay<T>::type, Executor>(
502 executor_arg_t(), ex, BOOST_ASIO_MOVE_CAST(T)(t));
505 /// Associate an object of type @c T with an execution context's executor.
506 template <typename ExecutionContext, typename T>
507 inline executor_binder<typename decay<T>::type,
508 typename ExecutionContext::executor_type>
509 bind_executor(ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(T) t,
510 typename enable_if<is_convertible<
511 ExecutionContext&, execution_context&>::value>::type* = 0)
513 return executor_binder<typename decay<T>::type,
514 typename ExecutionContext::executor_type>(
515 executor_arg_t(), ctx.get_executor(), BOOST_ASIO_MOVE_CAST(T)(t));
518 #if !defined(GENERATING_DOCUMENTATION)
520 template <typename T, typename Executor>
521 struct uses_executor<executor_binder<T, Executor>, Executor>
524 template <typename T, typename Executor, typename Signature>
525 class async_result<executor_binder<T, Executor>, Signature>
528 typedef executor_binder<
529 typename async_result<T, Signature>::completion_handler_type, Executor>
530 completion_handler_type;
532 typedef typename async_result<T, Signature>::return_type return_type;
534 explicit async_result(executor_binder<T, Executor>& b)
541 return target_.get();
545 async_result(const async_result&) BOOST_ASIO_DELETED;
546 async_result& operator=(const async_result&) BOOST_ASIO_DELETED;
548 async_result<T, Signature> target_;
551 #if !defined(BOOST_ASIO_NO_DEPRECATED)
553 template <typename T, typename Executor, typename Signature>
554 struct handler_type<executor_binder<T, Executor>, Signature>
556 typedef executor_binder<
557 typename handler_type<T, Signature>::type, Executor> type;
560 template <typename T, typename Executor>
561 class async_result<executor_binder<T, Executor> >
564 typedef typename async_result<T>::type type;
566 explicit async_result(executor_binder<T, Executor>& b)
573 return target_.get();
577 async_result<T> target_;
580 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
582 template <typename T, typename Executor, typename Allocator>
583 struct associated_allocator<executor_binder<T, Executor>, Allocator>
585 typedef typename associated_allocator<T, Allocator>::type type;
587 static type get(const executor_binder<T, Executor>& b,
588 const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
590 return associated_allocator<T, Allocator>::get(b.get(), a);
594 template <typename T, typename Executor, typename Executor1>
595 struct associated_executor<executor_binder<T, Executor>, Executor1>
597 typedef Executor type;
599 static type get(const executor_binder<T, Executor>& b,
600 const Executor1& = Executor1()) BOOST_ASIO_NOEXCEPT
602 return b.get_executor();
606 #endif // !defined(GENERATING_DOCUMENTATION)
611 #include <boost/asio/detail/pop_options.hpp>
613 #endif // BOOST_ASIO_BIND_EXECUTOR_HPP