• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // execution/blocking.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
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)
9 //
10 
11 #ifndef BOOST_ASIO_EXECUTION_BLOCKING_HPP
12 #define BOOST_ASIO_EXECUTION_BLOCKING_HPP
13 
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17 
18 #include <boost/asio/detail/config.hpp>
19 #include <boost/asio/detail/type_traits.hpp>
20 #include <boost/asio/execution/execute.hpp>
21 #include <boost/asio/execution/executor.hpp>
22 #include <boost/asio/execution/scheduler.hpp>
23 #include <boost/asio/execution/sender.hpp>
24 #include <boost/asio/is_applicable_property.hpp>
25 #include <boost/asio/prefer.hpp>
26 #include <boost/asio/query.hpp>
27 #include <boost/asio/require.hpp>
28 #include <boost/asio/traits/query_free.hpp>
29 #include <boost/asio/traits/query_member.hpp>
30 #include <boost/asio/traits/query_static_constexpr_member.hpp>
31 #include <boost/asio/traits/static_query.hpp>
32 #include <boost/asio/traits/static_require.hpp>
33 
34 #include <boost/asio/detail/push_options.hpp>
35 
36 namespace boost {
37 namespace asio {
38 
39 #if defined(GENERATING_DOCUMENTATION)
40 
41 namespace execution {
42 
43 /// A property to describe what guarantees an executor makes about the blocking
44 /// behaviour of their execution functions.
45 struct blocking_t
46 {
47   /// The blocking_t property applies to executors, senders, and schedulers.
48   template <typename T>
49   static constexpr bool is_applicable_property_v =
50     is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
51 
52   /// The top-level blocking_t property cannot be required.
53   static constexpr bool is_requirable = false;
54 
55   /// The top-level blocking_t property cannot be preferred.
56   static constexpr bool is_preferable = false;
57 
58   /// The type returned by queries against an @c any_executor.
59   typedef blocking_t polymorphic_query_result_type;
60 
61   /// A sub-property that indicates that invocation of an executor's execution
62   /// function may block pending completion of one or more invocations of the
63   /// submitted function object.
64   struct possibly_t
65   {
66     /// The blocking_t::possibly_t property applies to executors, senders, and
67     /// schedulers.
68     template <typename T>
69     static constexpr bool is_applicable_property_v =
70       is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
71 
72     /// The blocking_t::possibly_t property can be required.
73     static constexpr bool is_requirable = true;
74 
75     /// The blocking_t::possibly_t property can be preferred.
76     static constexpr bool is_preferable = true;
77 
78     /// The type returned by queries against an @c any_executor.
79     typedef blocking_t polymorphic_query_result_type;
80 
81     /// Default constructor.
82     constexpr possibly_t();
83 
84     /// Get the value associated with a property object.
85     /**
86      * @returns possibly_t();
87      */
88     static constexpr blocking_t value();
89   };
90 
91   /// A sub-property that indicates that invocation of an executor's execution
92   /// function shall block until completion of all invocations of the submitted
93   /// function object.
94   struct always_t
95   {
96     /// The blocking_t::always_t property applies to executors, senders, and
97     /// schedulers.
98     template <typename T>
99     static constexpr bool is_applicable_property_v =
100       is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
101 
102     /// The blocking_t::always_t property can be required.
103     static constexpr bool is_requirable = true;
104 
105     /// The blocking_t::always_t property can be preferred.
106     static constexpr bool is_preferable = false;
107 
108     /// The type returned by queries against an @c any_executor.
109     typedef blocking_t polymorphic_query_result_type;
110 
111     /// Default constructor.
112     constexpr always_t();
113 
114     /// Get the value associated with a property object.
115     /**
116      * @returns always_t();
117      */
118     static constexpr blocking_t value();
119   };
120 
121   /// A sub-property that indicates that invocation of an executor's execution
122   /// function shall not block pending completion of the invocations of the
123   /// submitted function object.
124   struct never_t
125   {
126     /// The blocking_t::never_t property applies to executors, senders, and
127     /// schedulers.
128     template <typename T>
129     static constexpr bool is_applicable_property_v =
130       is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
131 
132     /// The blocking_t::never_t property can be required.
133     static constexpr bool is_requirable = true;
134 
135     /// The blocking_t::never_t property can be preferred.
136     static constexpr bool is_preferable = true;
137 
138     /// The type returned by queries against an @c any_executor.
139     typedef blocking_t polymorphic_query_result_type;
140 
141     /// Default constructor.
142     constexpr never_t();
143 
144     /// Get the value associated with a property object.
145     /**
146      * @returns never_t();
147      */
148     static constexpr blocking_t value();
149   };
150 
151   /// A special value used for accessing the blocking_t::possibly_t property.
152   static constexpr possibly_t possibly;
153 
154   /// A special value used for accessing the blocking_t::always_t property.
155   static constexpr always_t always;
156 
157   /// A special value used for accessing the blocking_t::never_t property.
158   static constexpr never_t never;
159 
160   /// Default constructor.
161   constexpr blocking_t();
162 
163   /// Construct from a sub-property value.
164   constexpr blocking_t(possibly_t);
165 
166   /// Construct from a sub-property value.
167   constexpr blocking_t(always_t);
168 
169   /// Construct from a sub-property value.
170   constexpr blocking_t(never_t);
171 
172   /// Compare property values for equality.
173   friend constexpr bool operator==(
174       const blocking_t& a, const blocking_t& b) noexcept;
175 
176   /// Compare property values for inequality.
177   friend constexpr bool operator!=(
178       const blocking_t& a, const blocking_t& b) noexcept;
179 };
180 
181 /// A special value used for accessing the blocking_t property.
182 constexpr blocking_t blocking;
183 
184 } // namespace execution
185 
186 #else // defined(GENERATING_DOCUMENTATION)
187 
188 namespace execution {
189 namespace detail {
190 namespace blocking {
191 
192 template <int I> struct possibly_t;
193 template <int I> struct always_t;
194 template <int I> struct never_t;
195 
196 } // namespace blocking
197 namespace blocking_adaptation {
198 
199 template <int I> struct allowed_t;
200 
201 template <typename Executor, typename Function>
202 void blocking_execute(
203     BOOST_ASIO_MOVE_ARG(Executor) ex,
204     BOOST_ASIO_MOVE_ARG(Function) func);
205 
206 } // namespace blocking_adaptation
207 
208 template <int I = 0>
209 struct blocking_t
210 {
211 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
212   template <typename T>
213   BOOST_ASIO_STATIC_CONSTEXPR(bool,
214     is_applicable_property_v = is_executor<T>::value
215       || is_sender<T>::value || is_scheduler<T>::value);
216 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
217 
218   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);
219   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
220   typedef blocking_t polymorphic_query_result_type;
221 
222   typedef detail::blocking::possibly_t<I> possibly_t;
223   typedef detail::blocking::always_t<I> always_t;
224   typedef detail::blocking::never_t<I> never_t;
225 
226   BOOST_ASIO_CONSTEXPR blocking_t()
227     : value_(-1)
228   {
229   }
230 
231   BOOST_ASIO_CONSTEXPR blocking_t(possibly_t)
232     : value_(0)
233   {
234   }
235 
236   BOOST_ASIO_CONSTEXPR blocking_t(always_t)
237     : value_(1)
238   {
239   }
240 
241   BOOST_ASIO_CONSTEXPR blocking_t(never_t)
242     : value_(2)
243   {
244   }
245 
246 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
247   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
248   template <typename T>
249   static BOOST_ASIO_CONSTEXPR
250   typename traits::query_static_constexpr_member<T, blocking_t>::result_type
251   static_query()
252     BOOST_ASIO_NOEXCEPT_IF((
253       traits::query_static_constexpr_member<T, blocking_t>::is_noexcept))
254   {
255     return traits::query_static_constexpr_member<T, blocking_t>::value();
256   }
257 
258   template <typename T>
259   static BOOST_ASIO_CONSTEXPR
260   typename traits::static_query<T, possibly_t>::result_type
261   static_query(
262       typename enable_if<
263         !traits::query_static_constexpr_member<T, blocking_t>::is_valid
264           && !traits::query_member<T, blocking_t>::is_valid
265           && traits::static_query<T, possibly_t>::is_valid
266       >::type* = 0) BOOST_ASIO_NOEXCEPT
267   {
268     return traits::static_query<T, possibly_t>::value();
269   }
270 
271   template <typename T>
272   static BOOST_ASIO_CONSTEXPR
273   typename traits::static_query<T, always_t>::result_type
274   static_query(
275       typename enable_if<
276         !traits::query_static_constexpr_member<T, blocking_t>::is_valid
277           && !traits::query_member<T, blocking_t>::is_valid
278           && !traits::static_query<T, possibly_t>::is_valid
279           && traits::static_query<T, always_t>::is_valid
280       >::type* = 0) BOOST_ASIO_NOEXCEPT
281   {
282     return traits::static_query<T, always_t>::value();
283   }
284 
285   template <typename T>
286   static BOOST_ASIO_CONSTEXPR
287   typename traits::static_query<T, never_t>::result_type
288   static_query(
289       typename enable_if<
290         !traits::query_static_constexpr_member<T, blocking_t>::is_valid
291           && !traits::query_member<T, blocking_t>::is_valid
292           && !traits::static_query<T, possibly_t>::is_valid
293           && !traits::static_query<T, always_t>::is_valid
294           && traits::static_query<T, never_t>::is_valid
295       >::type* = 0) BOOST_ASIO_NOEXCEPT
296   {
297     return traits::static_query<T, never_t>::value();
298   }
299 
300   template <typename E, typename T = decltype(blocking_t::static_query<E>())>
301   static BOOST_ASIO_CONSTEXPR const T static_query_v
302     = blocking_t::static_query<E>();
303 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
304        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
305 
306   friend BOOST_ASIO_CONSTEXPR bool operator==(
307       const blocking_t& a, const blocking_t& b)
308   {
309     return a.value_ == b.value_;
310   }
311 
312   friend BOOST_ASIO_CONSTEXPR bool operator!=(
313       const blocking_t& a, const blocking_t& b)
314   {
315     return a.value_ != b.value_;
316   }
317 
318   struct convertible_from_blocking_t
319   {
320     BOOST_ASIO_CONSTEXPR convertible_from_blocking_t(blocking_t) {}
321   };
322 
323   template <typename Executor>
324   friend BOOST_ASIO_CONSTEXPR blocking_t query(
325       const Executor& ex, convertible_from_blocking_t,
326       typename enable_if<
327         can_query<const Executor&, possibly_t>::value
328       >::type* = 0)
329 #if !defined(__clang__) // Clang crashes if noexcept is used here.
330 #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified.
331     BOOST_ASIO_NOEXCEPT_IF((
332       is_nothrow_query<const Executor&, blocking_t<>::possibly_t>::value))
333 #else // defined(BOOST_ASIO_MSVC)
334     BOOST_ASIO_NOEXCEPT_IF((
335       is_nothrow_query<const Executor&, possibly_t>::value))
336 #endif // defined(BOOST_ASIO_MSVC)
337 #endif // !defined(__clang__)
338   {
339     return boost::asio::query(ex, possibly_t());
340   }
341 
342   template <typename Executor>
343   friend BOOST_ASIO_CONSTEXPR blocking_t query(
344       const Executor& ex, convertible_from_blocking_t,
345       typename enable_if<
346         !can_query<const Executor&, possibly_t>::value
347           && can_query<const Executor&, always_t>::value
348       >::type* = 0)
349 #if !defined(__clang__) // Clang crashes if noexcept is used here.
350 #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified.
351     BOOST_ASIO_NOEXCEPT_IF((
352       is_nothrow_query<const Executor&, blocking_t<>::always_t>::value))
353 #else // defined(BOOST_ASIO_MSVC)
354     BOOST_ASIO_NOEXCEPT_IF((
355       is_nothrow_query<const Executor&, always_t>::value))
356 #endif // defined(BOOST_ASIO_MSVC)
357 #endif // !defined(__clang__)
358   {
359     return boost::asio::query(ex, always_t());
360   }
361 
362   template <typename Executor>
363   friend BOOST_ASIO_CONSTEXPR blocking_t query(
364       const Executor& ex, convertible_from_blocking_t,
365       typename enable_if<
366         !can_query<const Executor&, possibly_t>::value
367           && !can_query<const Executor&, always_t>::value
368           && can_query<const Executor&, never_t>::value
369       >::type* = 0)
370 #if !defined(__clang__) // Clang crashes if noexcept is used here.
371 #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified.
372     BOOST_ASIO_NOEXCEPT_IF((
373       is_nothrow_query<const Executor&, blocking_t<>::never_t>::value))
374 #else // defined(BOOST_ASIO_MSVC)
375     BOOST_ASIO_NOEXCEPT_IF((
376       is_nothrow_query<const Executor&, never_t>::value))
377 #endif // defined(BOOST_ASIO_MSVC)
378 #endif // !defined(__clang__)
379   {
380     return boost::asio::query(ex, never_t());
381   }
382 
383   BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(possibly_t, possibly);
384   BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(always_t, always);
385   BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(never_t, never);
386 
387 #if !defined(BOOST_ASIO_HAS_CONSTEXPR)
388   static const blocking_t instance;
389 #endif // !defined(BOOST_ASIO_HAS_CONSTEXPR)
390 
391 private:
392   int value_;
393 };
394 
395 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
396   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
397 template <int I> template <typename E, typename T>
398 const T blocking_t<I>::static_query_v;
399 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
400        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
401 
402 #if !defined(BOOST_ASIO_HAS_CONSTEXPR)
403 template <int I>
404 const blocking_t<I> blocking_t<I>::instance;
405 #endif
406 
407 template <int I>
408 const typename blocking_t<I>::possibly_t blocking_t<I>::possibly;
409 
410 template <int I>
411 const typename blocking_t<I>::always_t blocking_t<I>::always;
412 
413 template <int I>
414 const typename blocking_t<I>::never_t blocking_t<I>::never;
415 
416 namespace blocking {
417 
418 template <int I = 0>
419 struct possibly_t
420 {
421 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
422   template <typename T>
423   BOOST_ASIO_STATIC_CONSTEXPR(bool,
424     is_applicable_property_v = is_executor<T>::value
425       || is_sender<T>::value || is_scheduler<T>::value);
426 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
427 
428   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
429   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
430   typedef blocking_t<I> polymorphic_query_result_type;
431 
432   BOOST_ASIO_CONSTEXPR possibly_t()
433   {
434   }
435 
436 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
437   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
438   template <typename T>
439   static BOOST_ASIO_CONSTEXPR
440   typename traits::query_static_constexpr_member<T, possibly_t>::result_type
441   static_query()
442     BOOST_ASIO_NOEXCEPT_IF((
443       traits::query_static_constexpr_member<T, possibly_t>::is_noexcept))
444   {
445     return traits::query_static_constexpr_member<T, possibly_t>::value();
446   }
447 
448   template <typename T>
449   static BOOST_ASIO_CONSTEXPR possibly_t static_query(
450       typename enable_if<
451         !traits::query_static_constexpr_member<T, possibly_t>::is_valid
452           && !traits::query_member<T, possibly_t>::is_valid
453           && !traits::query_free<T, possibly_t>::is_valid
454           && !can_query<T, always_t<I> >::value
455           && !can_query<T, never_t<I> >::value
456       >::type* = 0) BOOST_ASIO_NOEXCEPT
457   {
458     return possibly_t();
459   }
460 
461   template <typename E, typename T = decltype(possibly_t::static_query<E>())>
462   static BOOST_ASIO_CONSTEXPR const T static_query_v
463     = possibly_t::static_query<E>();
464 #endif // defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
465        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
466 
467   static BOOST_ASIO_CONSTEXPR blocking_t<I> value()
468   {
469     return possibly_t();
470   }
471 
472   friend BOOST_ASIO_CONSTEXPR bool operator==(
473       const possibly_t&, const possibly_t&)
474   {
475     return true;
476   }
477 
478   friend BOOST_ASIO_CONSTEXPR bool operator!=(
479       const possibly_t&, const possibly_t&)
480   {
481     return false;
482   }
483 
484   friend BOOST_ASIO_CONSTEXPR bool operator==(
485       const possibly_t&, const always_t<I>&)
486   {
487     return false;
488   }
489 
490   friend BOOST_ASIO_CONSTEXPR bool operator!=(
491       const possibly_t&, const always_t<I>&)
492   {
493     return true;
494   }
495 
496   friend BOOST_ASIO_CONSTEXPR bool operator==(
497       const possibly_t&, const never_t<I>&)
498   {
499     return false;
500   }
501 
502   friend BOOST_ASIO_CONSTEXPR bool operator!=(
503       const possibly_t&, const never_t<I>&)
504   {
505     return true;
506   }
507 };
508 
509 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
510   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
511 template <int I> template <typename E, typename T>
512 const T possibly_t<I>::static_query_v;
513 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
514        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
515 
516 template <typename Executor>
517 class adapter
518 {
519 public:
520   adapter(int, const Executor& e) BOOST_ASIO_NOEXCEPT
521     : executor_(e)
522   {
523   }
524 
525   adapter(const adapter& other) BOOST_ASIO_NOEXCEPT
526     : executor_(other.executor_)
527   {
528   }
529 
530 #if defined(BOOST_ASIO_HAS_MOVE)
531   adapter(adapter&& other) BOOST_ASIO_NOEXCEPT
532     : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_))
533   {
534   }
535 #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
536 
537   template <int I>
538   static BOOST_ASIO_CONSTEXPR always_t<I> query(
539       blocking_t<I>) BOOST_ASIO_NOEXCEPT
540   {
541     return always_t<I>();
542   }
543 
544   template <int I>
545   static BOOST_ASIO_CONSTEXPR always_t<I> query(
546       possibly_t<I>) BOOST_ASIO_NOEXCEPT
547   {
548     return always_t<I>();
549   }
550 
551   template <int I>
552   static BOOST_ASIO_CONSTEXPR always_t<I> query(
553       always_t<I>) BOOST_ASIO_NOEXCEPT
554   {
555     return always_t<I>();
556   }
557 
558   template <int I>
559   static BOOST_ASIO_CONSTEXPR always_t<I> query(
560       never_t<I>) BOOST_ASIO_NOEXCEPT
561   {
562     return always_t<I>();
563   }
564 
565   template <typename Property>
566   typename enable_if<
567     can_query<const Executor&, Property>::value,
568     typename query_result<const Executor&, Property>::type
569   >::type query(const Property& p) const
570     BOOST_ASIO_NOEXCEPT_IF((
571       is_nothrow_query<const Executor&, Property>::value))
572   {
573     return boost::asio::query(executor_, p);
574   }
575 
576   template <int I>
577   typename enable_if<
578     can_require<const Executor&, possibly_t<I> >::value,
579     typename require_result<const Executor&, possibly_t<I> >::type
580   >::type require(possibly_t<I>) const BOOST_ASIO_NOEXCEPT
581   {
582     return boost::asio::require(executor_, possibly_t<I>());
583   }
584 
585   template <int I>
586   typename enable_if<
587     can_require<const Executor&, never_t<I> >::value,
588     typename require_result<const Executor&, never_t<I> >::type
589   >::type require(never_t<I>) const BOOST_ASIO_NOEXCEPT
590   {
591     return boost::asio::require(executor_, never_t<I>());
592   }
593 
594   template <typename Property>
595   typename enable_if<
596     can_require<const Executor&, Property>::value,
597     adapter<typename decay<
598       typename require_result<const Executor&, Property>::type
599     >::type>
600   >::type require(const Property& p) const
601     BOOST_ASIO_NOEXCEPT_IF((
602       is_nothrow_require<const Executor&, Property>::value))
603   {
604     return adapter<typename decay<
605       typename require_result<const Executor&, Property>::type
606         >::type>(0, boost::asio::require(executor_, p));
607   }
608 
609   template <typename Property>
610   typename enable_if<
611     can_prefer<const Executor&, Property>::value,
612     adapter<typename decay<
613       typename prefer_result<const Executor&, Property>::type
614     >::type>
615   >::type prefer(const Property& p) const
616     BOOST_ASIO_NOEXCEPT_IF((
617       is_nothrow_prefer<const Executor&, Property>::value))
618   {
619     return adapter<typename decay<
620       typename prefer_result<const Executor&, Property>::type
621         >::type>(0, boost::asio::prefer(executor_, p));
622   }
623 
624   template <typename Function>
625   typename enable_if<
626     execution::can_execute<const Executor&, Function>::value
627   >::type execute(BOOST_ASIO_MOVE_ARG(Function) f) const
628   {
629     blocking_adaptation::blocking_execute(
630         executor_, BOOST_ASIO_MOVE_CAST(Function)(f));
631   }
632 
633   friend bool operator==(const adapter& a, const adapter& b) BOOST_ASIO_NOEXCEPT
634   {
635     return a.executor_ == b.executor_;
636   }
637 
638   friend bool operator!=(const adapter& a, const adapter& b) BOOST_ASIO_NOEXCEPT
639   {
640     return a.executor_ != b.executor_;
641   }
642 
643 private:
644   Executor executor_;
645 };
646 
647 template <int I = 0>
648 struct always_t
649 {
650 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
651   template <typename T>
652   BOOST_ASIO_STATIC_CONSTEXPR(bool,
653     is_applicable_property_v = is_executor<T>::value
654       || is_sender<T>::value || is_scheduler<T>::value);
655 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
656 
657   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
658   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
659   typedef blocking_t<I> polymorphic_query_result_type;
660 
661   BOOST_ASIO_CONSTEXPR always_t()
662   {
663   }
664 
665 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
666   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
667   template <typename T>
668   static BOOST_ASIO_CONSTEXPR
669   typename traits::query_static_constexpr_member<T, always_t>::result_type
670   static_query()
671     BOOST_ASIO_NOEXCEPT_IF((
672       traits::query_static_constexpr_member<T, always_t>::is_noexcept))
673   {
674     return traits::query_static_constexpr_member<T, always_t>::value();
675   }
676 
677   template <typename E, typename T = decltype(always_t::static_query<E>())>
678   static BOOST_ASIO_CONSTEXPR const T static_query_v
679     = always_t::static_query<E>();
680 #endif // defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
681        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
682 
683   static BOOST_ASIO_CONSTEXPR blocking_t<I> value()
684   {
685     return always_t();
686   }
687 
688   friend BOOST_ASIO_CONSTEXPR bool operator==(
689       const always_t&, const always_t&)
690   {
691     return true;
692   }
693 
694   friend BOOST_ASIO_CONSTEXPR bool operator!=(
695       const always_t&, const always_t&)
696   {
697     return false;
698   }
699 
700   friend BOOST_ASIO_CONSTEXPR bool operator==(
701       const always_t&, const possibly_t<I>&)
702   {
703     return false;
704   }
705 
706   friend BOOST_ASIO_CONSTEXPR bool operator!=(
707       const always_t&, const possibly_t<I>&)
708   {
709     return true;
710   }
711 
712   friend BOOST_ASIO_CONSTEXPR bool operator==(
713       const always_t&, const never_t<I>&)
714   {
715     return false;
716   }
717 
718   friend BOOST_ASIO_CONSTEXPR bool operator!=(
719       const always_t&, const never_t<I>&)
720   {
721     return true;
722   }
723 
724   template <typename Executor>
725   friend adapter<Executor> require(
726       const Executor& e, const always_t&,
727       typename enable_if<
728         is_executor<Executor>::value
729         && traits::static_require<
730           const Executor&,
731           blocking_adaptation::allowed_t<0>
732         >::is_valid
733       >::type* = 0)
734   {
735     return adapter<Executor>(0, e);
736   }
737 };
738 
739 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
740   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
741 template <int I> template <typename E, typename T>
742 const T always_t<I>::static_query_v;
743 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
744        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
745 
746 template <int I>
747 struct never_t
748 {
749 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
750   template <typename T>
751   BOOST_ASIO_STATIC_CONSTEXPR(bool,
752     is_applicable_property_v = is_executor<T>::value
753       || is_sender<T>::value || is_scheduler<T>::value);
754 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
755 
756   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
757   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
758   typedef blocking_t<I> polymorphic_query_result_type;
759 
760   BOOST_ASIO_CONSTEXPR never_t()
761   {
762   }
763 
764 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
765   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
766   template <typename T>
767   static BOOST_ASIO_CONSTEXPR
768   typename traits::query_static_constexpr_member<T, never_t>::result_type
769   static_query()
770     BOOST_ASIO_NOEXCEPT_IF((
771       traits::query_static_constexpr_member<T, never_t>::is_noexcept))
772   {
773     return traits::query_static_constexpr_member<T, never_t>::value();
774   }
775 
776   template <typename E, typename T = decltype(never_t::static_query<E>())>
777   static BOOST_ASIO_CONSTEXPR const T static_query_v
778     = never_t::static_query<E>();
779 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
780        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
781 
782   static BOOST_ASIO_CONSTEXPR blocking_t<I> value()
783   {
784     return never_t();
785   }
786 
787   friend BOOST_ASIO_CONSTEXPR bool operator==(
788       const never_t&, const never_t&)
789   {
790     return true;
791   }
792 
793   friend BOOST_ASIO_CONSTEXPR bool operator!=(
794       const never_t&, const never_t&)
795   {
796     return false;
797   }
798 
799   friend BOOST_ASIO_CONSTEXPR bool operator==(
800       const never_t&, const possibly_t<I>&)
801   {
802     return false;
803   }
804 
805   friend BOOST_ASIO_CONSTEXPR bool operator!=(
806       const never_t&, const possibly_t<I>&)
807   {
808     return true;
809   }
810 
811   friend BOOST_ASIO_CONSTEXPR bool operator==(
812       const never_t&, const always_t<I>&)
813   {
814     return false;
815   }
816 
817   friend BOOST_ASIO_CONSTEXPR bool operator!=(
818       const never_t&, const always_t<I>&)
819   {
820     return true;
821   }
822 };
823 
824 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
825   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
826 template <int I> template <typename E, typename T>
827 const T never_t<I>::static_query_v;
828 #endif // defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
829 
830 } // namespace blocking
831 } // namespace detail
832 
833 typedef detail::blocking_t<> blocking_t;
834 
835 #if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
836 constexpr blocking_t blocking;
837 #else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
838 namespace { static const blocking_t& blocking = blocking_t::instance; }
839 #endif
840 
841 } // namespace execution
842 
843 #if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
844 
845 template <typename T>
846 struct is_applicable_property<T, execution::blocking_t>
847   : integral_constant<bool,
848       execution::is_executor<T>::value
849         || execution::is_sender<T>::value
850         || execution::is_scheduler<T>::value>
851 {
852 };
853 
854 template <typename T>
855 struct is_applicable_property<T, execution::blocking_t::possibly_t>
856   : integral_constant<bool,
857       execution::is_executor<T>::value
858         || execution::is_sender<T>::value
859         || execution::is_scheduler<T>::value>
860 {
861 };
862 
863 template <typename T>
864 struct is_applicable_property<T, execution::blocking_t::always_t>
865   : integral_constant<bool,
866       execution::is_executor<T>::value
867         || execution::is_sender<T>::value
868         || execution::is_scheduler<T>::value>
869 {
870 };
871 
872 template <typename T>
873 struct is_applicable_property<T, execution::blocking_t::never_t>
874   : integral_constant<bool,
875       execution::is_executor<T>::value
876         || execution::is_sender<T>::value
877         || execution::is_scheduler<T>::value>
878 {
879 };
880 
881 #endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
882 
883 namespace traits {
884 
885 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
886 
887 template <typename T>
888 struct query_free_default<T, execution::blocking_t,
889   typename enable_if<
890     can_query<T, execution::blocking_t::possibly_t>::value
891   >::type>
892 {
893   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
894   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
895     (is_nothrow_query<T, execution::blocking_t::possibly_t>::value));
896 
897   typedef execution::blocking_t result_type;
898 };
899 
900 template <typename T>
901 struct query_free_default<T, execution::blocking_t,
902   typename enable_if<
903     !can_query<T, execution::blocking_t::possibly_t>::value
904       && can_query<T, execution::blocking_t::always_t>::value
905   >::type>
906 {
907   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
908   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
909     (is_nothrow_query<T, execution::blocking_t::always_t>::value));
910 
911   typedef execution::blocking_t result_type;
912 };
913 
914 template <typename T>
915 struct query_free_default<T, execution::blocking_t,
916   typename enable_if<
917     !can_query<T, execution::blocking_t::possibly_t>::value
918       && !can_query<T, execution::blocking_t::always_t>::value
919       && can_query<T, execution::blocking_t::never_t>::value
920   >::type>
921 {
922   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
923   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
924     (is_nothrow_query<T, execution::blocking_t::never_t>::value));
925 
926   typedef execution::blocking_t result_type;
927 };
928 
929 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
930 
931 #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
932   || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
933 
934 template <typename T>
935 struct static_query<T, execution::blocking_t,
936   typename enable_if<
937     traits::query_static_constexpr_member<T,
938       execution::blocking_t>::is_valid
939   >::type>
940 {
941   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
942   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
943 
944   typedef typename traits::query_static_constexpr_member<T,
945     execution::blocking_t>::result_type result_type;
946 
947   static BOOST_ASIO_CONSTEXPR result_type value()
948   {
949     return traits::query_static_constexpr_member<T,
950       execution::blocking_t>::value();
951   }
952 };
953 
954 template <typename T>
955 struct static_query<T, execution::blocking_t,
956   typename enable_if<
957     !traits::query_static_constexpr_member<T, execution::blocking_t>::is_valid
958       && !traits::query_member<T, execution::blocking_t>::is_valid
959       && traits::static_query<T, execution::blocking_t::possibly_t>::is_valid
960   >::type>
961 {
962   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
963   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
964 
965   typedef typename traits::static_query<T,
966     execution::blocking_t::possibly_t>::result_type result_type;
967 
968   static BOOST_ASIO_CONSTEXPR result_type value()
969   {
970     return traits::static_query<T, execution::blocking_t::possibly_t>::value();
971   }
972 };
973 
974 template <typename T>
975 struct static_query<T, execution::blocking_t,
976   typename enable_if<
977     !traits::query_static_constexpr_member<T, execution::blocking_t>::is_valid
978       && !traits::query_member<T, execution::blocking_t>::is_valid
979       && !traits::static_query<T, execution::blocking_t::possibly_t>::is_valid
980       && traits::static_query<T, execution::blocking_t::always_t>::is_valid
981   >::type>
982 {
983   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
984   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
985 
986   typedef typename traits::static_query<T,
987     execution::blocking_t::always_t>::result_type result_type;
988 
989   static BOOST_ASIO_CONSTEXPR result_type value()
990   {
991     return traits::static_query<T, execution::blocking_t::always_t>::value();
992   }
993 };
994 
995 template <typename T>
996 struct static_query<T, execution::blocking_t,
997   typename enable_if<
998     !traits::query_static_constexpr_member<T, execution::blocking_t>::is_valid
999       && !traits::query_member<T, execution::blocking_t>::is_valid
1000       && !traits::static_query<T, execution::blocking_t::possibly_t>::is_valid
1001       && !traits::static_query<T, execution::blocking_t::always_t>::is_valid
1002       && traits::static_query<T, execution::blocking_t::never_t>::is_valid
1003   >::type>
1004 {
1005   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1006   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1007 
1008   typedef typename traits::static_query<T,
1009     execution::blocking_t::never_t>::result_type result_type;
1010 
1011   static BOOST_ASIO_CONSTEXPR result_type value()
1012   {
1013     return traits::static_query<T, execution::blocking_t::never_t>::value();
1014   }
1015 };
1016 
1017 template <typename T>
1018 struct static_query<T, execution::blocking_t::possibly_t,
1019   typename enable_if<
1020     traits::query_static_constexpr_member<T,
1021       execution::blocking_t::possibly_t>::is_valid
1022   >::type>
1023 {
1024   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1025   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1026 
1027   typedef typename traits::query_static_constexpr_member<T,
1028     execution::blocking_t::possibly_t>::result_type result_type;
1029 
1030   static BOOST_ASIO_CONSTEXPR result_type value()
1031   {
1032     return traits::query_static_constexpr_member<T,
1033       execution::blocking_t::possibly_t>::value();
1034   }
1035 };
1036 
1037 template <typename T>
1038 struct static_query<T, execution::blocking_t::possibly_t,
1039   typename enable_if<
1040     !traits::query_static_constexpr_member<T,
1041       execution::blocking_t::possibly_t>::is_valid
1042       && !traits::query_member<T, execution::blocking_t::possibly_t>::is_valid
1043       && !traits::query_free<T, execution::blocking_t::possibly_t>::is_valid
1044       && !can_query<T, execution::blocking_t::always_t>::value
1045       && !can_query<T, execution::blocking_t::never_t>::value
1046   >::type>
1047 {
1048   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1049   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1050 
1051   typedef execution::blocking_t::possibly_t result_type;
1052 
1053   static BOOST_ASIO_CONSTEXPR result_type value()
1054   {
1055     return result_type();
1056   }
1057 };
1058 
1059 template <typename T>
1060 struct static_query<T, execution::blocking_t::always_t,
1061   typename enable_if<
1062     traits::query_static_constexpr_member<T,
1063       execution::blocking_t::always_t>::is_valid
1064   >::type>
1065 {
1066   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1067   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1068 
1069   typedef typename traits::query_static_constexpr_member<T,
1070     execution::blocking_t::always_t>::result_type result_type;
1071 
1072   static BOOST_ASIO_CONSTEXPR result_type value()
1073   {
1074     return traits::query_static_constexpr_member<T,
1075       execution::blocking_t::always_t>::value();
1076   }
1077 };
1078 
1079 template <typename T>
1080 struct static_query<T, execution::blocking_t::never_t,
1081   typename enable_if<
1082     traits::query_static_constexpr_member<T,
1083       execution::blocking_t::never_t>::is_valid
1084   >::type>
1085 {
1086   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1087   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1088 
1089   typedef typename traits::query_static_constexpr_member<T,
1090     execution::blocking_t::never_t>::result_type result_type;
1091 
1092   static BOOST_ASIO_CONSTEXPR result_type value()
1093   {
1094     return traits::query_static_constexpr_member<T,
1095       execution::blocking_t::never_t>::value();
1096   }
1097 };
1098 
1099 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
1100        //   || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
1101 
1102 #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
1103 
1104 template <typename T>
1105 struct static_require<T, execution::blocking_t::possibly_t,
1106   typename enable_if<
1107     static_query<T, execution::blocking_t::possibly_t>::is_valid
1108   >::type>
1109 {
1110   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid =
1111     (is_same<typename static_query<T,
1112       execution::blocking_t::possibly_t>::result_type,
1113         execution::blocking_t::possibly_t>::value));
1114 };
1115 
1116 template <typename T>
1117 struct static_require<T, execution::blocking_t::always_t,
1118   typename enable_if<
1119     static_query<T, execution::blocking_t::always_t>::is_valid
1120   >::type>
1121 {
1122   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid =
1123     (is_same<typename static_query<T,
1124       execution::blocking_t::always_t>::result_type,
1125         execution::blocking_t::always_t>::value));
1126 };
1127 
1128 template <typename T>
1129 struct static_require<T, execution::blocking_t::never_t,
1130   typename enable_if<
1131     static_query<T, execution::blocking_t::never_t>::is_valid
1132   >::type>
1133 {
1134   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid =
1135     (is_same<typename static_query<T,
1136       execution::blocking_t::never_t>::result_type,
1137         execution::blocking_t::never_t>::value));
1138 };
1139 
1140 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
1141 
1142 #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)
1143 
1144 template <typename T>
1145 struct require_free_default<T, execution::blocking_t::always_t,
1146   typename enable_if<
1147     is_same<T, typename decay<T>::type>::value
1148       && execution::is_executor<T>::value
1149       && traits::static_require<
1150           const T&,
1151           execution::detail::blocking_adaptation::allowed_t<0>
1152         >::is_valid
1153   >::type>
1154 {
1155   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1156   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
1157   typedef execution::detail::blocking::adapter<T> result_type;
1158 };
1159 
1160 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)
1161 
1162 #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
1163 
1164 template <typename Executor>
1165 struct equality_comparable<
1166   execution::detail::blocking::adapter<Executor> >
1167 {
1168   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1169   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1170 };
1171 
1172 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
1173 
1174 #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
1175 
1176 template <typename Executor, typename Function>
1177 struct execute_member<
1178   execution::detail::blocking::adapter<Executor>, Function>
1179 {
1180   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1181   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
1182   typedef void result_type;
1183 };
1184 
1185 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
1186 
1187 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
1188 
1189 template <typename Executor, int I>
1190 struct query_static_constexpr_member<
1191   execution::detail::blocking::adapter<Executor>,
1192   execution::detail::blocking_t<I> >
1193 {
1194   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1195   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1196   typedef execution::blocking_t::always_t result_type;
1197 
1198   static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT
1199   {
1200     return result_type();
1201   }
1202 };
1203 
1204 template <typename Executor, int I>
1205 struct query_static_constexpr_member<
1206   execution::detail::blocking::adapter<Executor>,
1207   execution::detail::blocking::always_t<I> >
1208 {
1209   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1210   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1211   typedef execution::blocking_t::always_t result_type;
1212 
1213   static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT
1214   {
1215     return result_type();
1216   }
1217 };
1218 
1219 template <typename Executor, int I>
1220 struct query_static_constexpr_member<
1221   execution::detail::blocking::adapter<Executor>,
1222   execution::detail::blocking::possibly_t<I> >
1223 {
1224   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1225   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1226   typedef execution::blocking_t::always_t result_type;
1227 
1228   static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT
1229   {
1230     return result_type();
1231   }
1232 };
1233 
1234 template <typename Executor, int I>
1235 struct query_static_constexpr_member<
1236   execution::detail::blocking::adapter<Executor>,
1237   execution::detail::blocking::never_t<I> >
1238 {
1239   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1240   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1241   typedef execution::blocking_t::always_t result_type;
1242 
1243   static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT
1244   {
1245     return result_type();
1246   }
1247 };
1248 
1249 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
1250 
1251 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
1252 
1253 template <typename Executor, typename Property>
1254 struct query_member<
1255   execution::detail::blocking::adapter<Executor>, Property,
1256   typename enable_if<
1257     can_query<const Executor&, Property>::value
1258   >::type>
1259 {
1260   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1261   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
1262       (is_nothrow_query<Executor, Property>::value));
1263   typedef typename query_result<Executor, Property>::type result_type;
1264 };
1265 
1266 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
1267 
1268 #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
1269 
1270 template <typename Executor, int I>
1271 struct require_member<
1272   execution::detail::blocking::adapter<Executor>,
1273   execution::detail::blocking::possibly_t<I>,
1274   typename enable_if<
1275     can_require<
1276       const Executor&,
1277       execution::detail::blocking::possibly_t<I>
1278     >::value
1279   >::type>
1280 {
1281   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1282   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
1283       (is_nothrow_require<const Executor&,
1284         execution::detail::blocking::possibly_t<I> >::value));
1285   typedef typename require_result<const Executor&,
1286     execution::detail::blocking::possibly_t<I> >::type result_type;
1287 };
1288 
1289 template <typename Executor, int I>
1290 struct require_member<
1291   execution::detail::blocking::adapter<Executor>,
1292   execution::detail::blocking::never_t<I>,
1293   typename enable_if<
1294     can_require<
1295       const Executor&,
1296       execution::detail::blocking::never_t<I>
1297     >::value
1298   >::type>
1299 {
1300   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1301   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
1302       (is_nothrow_require<const Executor&,
1303         execution::detail::blocking::never_t<I> >::value));
1304   typedef typename require_result<const Executor&,
1305     execution::detail::blocking::never_t<I> >::type result_type;
1306 };
1307 
1308 template <typename Executor, typename Property>
1309 struct require_member<
1310   execution::detail::blocking::adapter<Executor>, Property,
1311   typename enable_if<
1312     can_require<const Executor&, Property>::value
1313   >::type>
1314 {
1315   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1316   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
1317       (is_nothrow_require<Executor, Property>::value));
1318   typedef execution::detail::blocking::adapter<typename decay<
1319     typename require_result<Executor, Property>::type
1320       >::type> result_type;
1321 };
1322 
1323 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
1324 
1325 #if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
1326 
1327 template <typename Executor, typename Property>
1328 struct prefer_member<
1329   execution::detail::blocking::adapter<Executor>, Property,
1330   typename enable_if<
1331     can_prefer<const Executor&, Property>::value
1332   >::type>
1333 {
1334   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1335   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
1336       (is_nothrow_prefer<Executor, Property>::value));
1337   typedef execution::detail::blocking::adapter<typename decay<
1338     typename prefer_result<Executor, Property>::type
1339       >::type> result_type;
1340 };
1341 
1342 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
1343 
1344 } // namespace traits
1345 
1346 #endif // defined(GENERATING_DOCUMENTATION)
1347 
1348 } // namespace asio
1349 } // namespace boost
1350 
1351 #include <boost/asio/detail/pop_options.hpp>
1352 
1353 #endif // BOOST_ASIO_EXECUTION_BLOCKING_HPP
1354