• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // prefer.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_PREFER_HPP
12 #define BOOST_ASIO_PREFER_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/is_applicable_property.hpp>
21 #include <boost/asio/traits/prefer_free.hpp>
22 #include <boost/asio/traits/prefer_member.hpp>
23 #include <boost/asio/traits/require_free.hpp>
24 #include <boost/asio/traits/require_member.hpp>
25 #include <boost/asio/traits/static_require.hpp>
26 
27 #include <boost/asio/detail/push_options.hpp>
28 
29 #if defined(GENERATING_DOCUMENTATION)
30 
31 namespace boost {
32 namespace asio {
33 
34 /// A customisation point that attempts to apply a property to an object.
35 /**
36  * The name <tt>prefer</tt> denotes a customisation point object. The
37  * expression <tt>boost::asio::prefer(E, P0, Pn...)</tt> for some subexpressions
38  * <tt>E</tt> and <tt>P0</tt>, and where <tt>Pn...</tt> represents <tt>N</tt>
39  * subexpressions (where <tt>N</tt> is 0 or more, and with types <tt>T =
40  * decay_t<decltype(E)></tt> and <tt>Prop0 = decay_t<decltype(P0)></tt>) is
41  * expression-equivalent to:
42  *
43  * @li If <tt>is_applicable_property_v<T, Prop0> && Prop0::is_preferable</tt> is
44  *   not a well-formed constant expression with value <tt>true</tt>,
45  *   <tt>boost::asio::prefer(E, P0, Pn...)</tt> is ill-formed.
46  *
47  * @li Otherwise, <tt>E</tt> if <tt>N == 0</tt> and the expression
48  *   <tt>Prop0::template static_query_v<T> == Prop0::value()</tt> is a
49  *   well-formed constant expression with value <tt>true</tt>.
50  *
51  * @li Otherwise, <tt>(E).require(P0)</tt> if <tt>N == 0</tt> and the expression
52  *   <tt>(E).require(P0)</tt> is a valid expression.
53  *
54  * @li Otherwise, <tt>require(E, P0)</tt> if <tt>N == 0</tt> and the expression
55  *   <tt>require(E, P0)</tt> is a valid expression with overload resolution
56  *   performed in a context that does not include the declaration of the
57  *   <tt>require</tt> customization point object.
58  *
59  * @li Otherwise, <tt>(E).prefer(P0)</tt> if <tt>N == 0</tt> and the expression
60  *   <tt>(E).prefer(P0)</tt> is a valid expression.
61  *
62  * @li Otherwise, <tt>prefer(E, P0)</tt> if <tt>N == 0</tt> and the expression
63  *   <tt>prefer(E, P0)</tt> is a valid expression with overload resolution
64  *   performed in a context that does not include the declaration of the
65  *   <tt>prefer</tt> customization point object.
66  *
67  * @li Otherwise, <tt>E</tt> if <tt>N == 0</tt>.
68  *
69  * @li Otherwise,
70  *   <tt>boost::asio::prefer(boost::asio::prefer(E, P0), Pn...)</tt>
71  *   if <tt>N > 0</tt> and the expression
72  *   <tt>boost::asio::prefer(boost::asio::prefer(E, P0), Pn...)</tt>
73  *   is a valid expression.
74  *
75  * @li Otherwise, <tt>boost::asio::prefer(E, P0, Pn...)</tt> is ill-formed.
76  */
77 inline constexpr unspecified prefer = unspecified;
78 
79 /// A type trait that determines whether a @c prefer expression is well-formed.
80 /**
81  * Class template @c can_prefer is a trait that is derived from
82  * @c true_type if the expression <tt>boost::asio::prefer(std::declval<T>(),
83  * std::declval<Properties>()...)</tt> is well formed; otherwise @c false_type.
84  */
85 template <typename T, typename... Properties>
86 struct can_prefer :
87   integral_constant<bool, automatically_determined>
88 {
89 };
90 
91 /// A type trait that determines whether a @c prefer expression will not throw.
92 /**
93  * Class template @c is_nothrow_prefer is a trait that is derived from
94  * @c true_type if the expression <tt>boost::asio::prefer(std::declval<T>(),
95  * std::declval<Properties>()...)</tt> is @c noexcept; otherwise @c false_type.
96  */
97 template <typename T, typename... Properties>
98 struct is_nothrow_prefer :
99   integral_constant<bool, automatically_determined>
100 {
101 };
102 
103 /// A type trait that determines the result type of a @c prefer expression.
104 /**
105  * Class template @c prefer_result is a trait that determines the result
106  * type of the expression <tt>boost::asio::prefer(std::declval<T>(),
107  * std::declval<Properties>()...)</tt>.
108  */
109 template <typename T, typename... Properties>
110 struct prefer_result
111 {
112   /// The result of the @c prefer expression.
113   typedef automatically_determined type;
114 };
115 
116 } // namespace asio
117 } // namespace boost
118 
119 #else // defined(GENERATING_DOCUMENTATION)
120 
121 namespace asio_prefer_fn {
122 
123 using boost::asio::decay;
124 using boost::asio::declval;
125 using boost::asio::enable_if;
126 using boost::asio::is_applicable_property;
127 using boost::asio::traits::prefer_free;
128 using boost::asio::traits::prefer_member;
129 using boost::asio::traits::require_free;
130 using boost::asio::traits::require_member;
131 using boost::asio::traits::static_require;
132 
133 void prefer();
134 void require();
135 
136 enum overload_type
137 {
138   identity,
139   call_require_member,
140   call_require_free,
141   call_prefer_member,
142   call_prefer_free,
143   two_props,
144   n_props,
145   ill_formed
146 };
147 
148 template <typename T, typename Properties, typename = void>
149 struct call_traits
150 {
151   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
152   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
153   typedef void result_type;
154 };
155 
156 template <typename T, typename Property>
157 struct call_traits<T, void(Property),
158   typename enable_if<
159     (
160       is_applicable_property<
161         typename decay<T>::type,
162         typename decay<Property>::type
163       >::value
164       &&
165       decay<Property>::type::is_preferable
166       &&
167       static_require<T, Property>::is_valid
168     )
169   >::type>
170 {
171   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = identity);
172   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
173 
174 #if defined(BOOST_ASIO_HAS_MOVE)
175   typedef BOOST_ASIO_MOVE_ARG(T) result_type;
176 #else // defined(BOOST_ASIO_HAS_MOVE)
177   typedef BOOST_ASIO_MOVE_ARG(typename decay<T>::type) result_type;
178 #endif // defined(BOOST_ASIO_HAS_MOVE)
179 };
180 
181 template <typename T, typename Property>
182 struct call_traits<T, void(Property),
183   typename enable_if<
184     (
185       is_applicable_property<
186         typename decay<T>::type,
187         typename decay<Property>::type
188       >::value
189       &&
190       decay<Property>::type::is_preferable
191       &&
192       !static_require<T, Property>::is_valid
193       &&
194       require_member<T, Property>::is_valid
195     )
196   >::type> :
197   require_member<T, Property>
198 {
199   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_require_member);
200 };
201 
202 template <typename T, typename Property>
203 struct call_traits<T, void(Property),
204   typename enable_if<
205     (
206       is_applicable_property<
207         typename decay<T>::type,
208         typename decay<Property>::type
209       >::value
210       &&
211       decay<Property>::type::is_preferable
212       &&
213       !static_require<T, Property>::is_valid
214       &&
215       !require_member<T, Property>::is_valid
216       &&
217       require_free<T, Property>::is_valid
218     )
219   >::type> :
220   require_free<T, Property>
221 {
222   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_require_free);
223 };
224 
225 template <typename T, typename Property>
226 struct call_traits<T, void(Property),
227   typename enable_if<
228     (
229       is_applicable_property<
230         typename decay<T>::type,
231         typename decay<Property>::type
232       >::value
233       &&
234       decay<Property>::type::is_preferable
235       &&
236       !static_require<T, Property>::is_valid
237       &&
238       !require_member<T, Property>::is_valid
239       &&
240       !require_free<T, Property>::is_valid
241       &&
242       prefer_member<T, Property>::is_valid
243     )
244   >::type> :
245   prefer_member<T, Property>
246 {
247   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_prefer_member);
248 };
249 
250 template <typename T, typename Property>
251 struct call_traits<T, void(Property),
252   typename enable_if<
253     (
254       is_applicable_property<
255         typename decay<T>::type,
256         typename decay<Property>::type
257       >::value
258       &&
259       decay<Property>::type::is_preferable
260       &&
261       !static_require<T, Property>::is_valid
262       &&
263       !require_member<T, Property>::is_valid
264       &&
265       !require_free<T, Property>::is_valid
266       &&
267       !prefer_member<T, Property>::is_valid
268       &&
269       prefer_free<T, Property>::is_valid
270     )
271   >::type> :
272   prefer_free<T, Property>
273 {
274   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_prefer_free);
275 };
276 
277 template <typename T, typename Property>
278 struct call_traits<T, void(Property),
279   typename enable_if<
280     (
281       is_applicable_property<
282         typename decay<T>::type,
283         typename decay<Property>::type
284       >::value
285       &&
286       decay<Property>::type::is_preferable
287       &&
288       !static_require<T, Property>::is_valid
289       &&
290       !require_member<T, Property>::is_valid
291       &&
292       !require_free<T, Property>::is_valid
293       &&
294       !prefer_member<T, Property>::is_valid
295       &&
296       !prefer_free<T, Property>::is_valid
297     )
298   >::type>
299 {
300   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = identity);
301   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
302 
303 #if defined(BOOST_ASIO_HAS_MOVE)
304   typedef BOOST_ASIO_MOVE_ARG(T) result_type;
305 #else // defined(BOOST_ASIO_HAS_MOVE)
306   typedef BOOST_ASIO_MOVE_ARG(typename decay<T>::type) result_type;
307 #endif // defined(BOOST_ASIO_HAS_MOVE)
308 };
309 
310 template <typename T, typename P0, typename P1>
311 struct call_traits<T, void(P0, P1),
312   typename enable_if<
313     call_traits<T, void(P0)>::overload != ill_formed
314     &&
315     call_traits<
316       typename call_traits<T, void(P0)>::result_type,
317       void(P1)
318     >::overload != ill_formed
319   >::type>
320 {
321   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = two_props);
322 
323   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
324     (
325       call_traits<T, void(P0)>::is_noexcept
326       &&
327       call_traits<
328         typename call_traits<T, void(P0)>::result_type,
329         void(P1)
330       >::is_noexcept
331     ));
332 
333   typedef typename decay<
334     typename call_traits<
335       typename call_traits<T, void(P0)>::result_type,
336       void(P1)
337     >::result_type
338   >::type result_type;
339 };
340 
341 template <typename T, typename P0, typename P1, typename BOOST_ASIO_ELLIPSIS PN>
342 struct call_traits<T, void(P0, P1, PN BOOST_ASIO_ELLIPSIS),
343   typename enable_if<
344     call_traits<T, void(P0)>::overload != ill_formed
345     &&
346     call_traits<
347       typename call_traits<T, void(P0)>::result_type,
348       void(P1, PN BOOST_ASIO_ELLIPSIS)
349     >::overload != ill_formed
350   >::type>
351 {
352   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = n_props);
353 
354   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
355     (
356       call_traits<T, void(P0)>::is_noexcept
357       &&
358       call_traits<
359         typename call_traits<T, void(P0)>::result_type,
360         void(P1, PN BOOST_ASIO_ELLIPSIS)
361       >::is_noexcept
362     ));
363 
364   typedef typename decay<
365     typename call_traits<
366       typename call_traits<T, void(P0)>::result_type,
367       void(P1, PN BOOST_ASIO_ELLIPSIS)
368     >::result_type
369   >::type result_type;
370 };
371 
372 struct impl
373 {
374   template <typename T, typename Property>
375   BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if<
376     call_traits<T, void(Property)>::overload == identity,
377     typename call_traits<T, void(Property)>::result_type
378   >::type
operator ()asio_prefer_fn::impl379   operator()(
380       BOOST_ASIO_MOVE_ARG(T) t,
381       BOOST_ASIO_MOVE_ARG(Property)) const
382     BOOST_ASIO_NOEXCEPT_IF((
383       call_traits<T, void(Property)>::is_noexcept))
384   {
385     return BOOST_ASIO_MOVE_CAST(T)(t);
386   }
387 
388   template <typename T, typename Property>
389   BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if<
390     call_traits<T, void(Property)>::overload == call_require_member,
391     typename call_traits<T, void(Property)>::result_type
392   >::type
operator ()asio_prefer_fn::impl393   operator()(
394       BOOST_ASIO_MOVE_ARG(T) t,
395       BOOST_ASIO_MOVE_ARG(Property) p) const
396     BOOST_ASIO_NOEXCEPT_IF((
397       call_traits<T, void(Property)>::is_noexcept))
398   {
399     return BOOST_ASIO_MOVE_CAST(T)(t).require(
400         BOOST_ASIO_MOVE_CAST(Property)(p));
401   }
402 
403   template <typename T, typename Property>
404   BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if<
405     call_traits<T, void(Property)>::overload == call_require_free,
406     typename call_traits<T, void(Property)>::result_type
407   >::type
operator ()asio_prefer_fn::impl408   operator()(
409       BOOST_ASIO_MOVE_ARG(T) t,
410       BOOST_ASIO_MOVE_ARG(Property) p) const
411     BOOST_ASIO_NOEXCEPT_IF((
412       call_traits<T, void(Property)>::is_noexcept))
413   {
414     return require(
415         BOOST_ASIO_MOVE_CAST(T)(t),
416         BOOST_ASIO_MOVE_CAST(Property)(p));
417   }
418 
419   template <typename T, typename Property>
420   BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if<
421     call_traits<T, void(Property)>::overload == call_prefer_member,
422     typename call_traits<T, void(Property)>::result_type
423   >::type
operator ()asio_prefer_fn::impl424   operator()(
425       BOOST_ASIO_MOVE_ARG(T) t,
426       BOOST_ASIO_MOVE_ARG(Property) p) const
427     BOOST_ASIO_NOEXCEPT_IF((
428       call_traits<T, void(Property)>::is_noexcept))
429   {
430     return BOOST_ASIO_MOVE_CAST(T)(t).prefer(
431         BOOST_ASIO_MOVE_CAST(Property)(p));
432   }
433 
434   template <typename T, typename Property>
435   BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if<
436     call_traits<T, void(Property)>::overload == call_prefer_free,
437     typename call_traits<T, void(Property)>::result_type
438   >::type
operator ()asio_prefer_fn::impl439   operator()(
440       BOOST_ASIO_MOVE_ARG(T) t,
441       BOOST_ASIO_MOVE_ARG(Property) p) const
442     BOOST_ASIO_NOEXCEPT_IF((
443       call_traits<T, void(Property)>::is_noexcept))
444   {
445     return prefer(
446         BOOST_ASIO_MOVE_CAST(T)(t),
447         BOOST_ASIO_MOVE_CAST(Property)(p));
448   }
449 
450   template <typename T, typename P0, typename P1>
451   BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if<
452     call_traits<T, void(P0, P1)>::overload == two_props,
453     typename call_traits<T, void(P0, P1)>::result_type
454   >::type
operator ()asio_prefer_fn::impl455   operator()(
456       BOOST_ASIO_MOVE_ARG(T) t,
457       BOOST_ASIO_MOVE_ARG(P0) p0,
458       BOOST_ASIO_MOVE_ARG(P1) p1) const
459     BOOST_ASIO_NOEXCEPT_IF((
460       call_traits<T, void(P0, P1)>::is_noexcept))
461   {
462     return (*this)(
463         (*this)(
464           BOOST_ASIO_MOVE_CAST(T)(t),
465           BOOST_ASIO_MOVE_CAST(P0)(p0)),
466         BOOST_ASIO_MOVE_CAST(P1)(p1));
467   }
468 
469   template <typename T, typename P0, typename P1,
470     typename BOOST_ASIO_ELLIPSIS PN>
471   BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if<
472     call_traits<T, void(P0, P1, PN BOOST_ASIO_ELLIPSIS)>::overload == n_props,
473     typename call_traits<T, void(P0, P1, PN BOOST_ASIO_ELLIPSIS)>::result_type
474   >::type
operator ()asio_prefer_fn::impl475   operator()(
476       BOOST_ASIO_MOVE_ARG(T) t,
477       BOOST_ASIO_MOVE_ARG(P0) p0,
478       BOOST_ASIO_MOVE_ARG(P1) p1,
479       BOOST_ASIO_MOVE_ARG(PN) BOOST_ASIO_ELLIPSIS pn) const
480     BOOST_ASIO_NOEXCEPT_IF((
481       call_traits<T, void(P0, P1, PN BOOST_ASIO_ELLIPSIS)>::is_noexcept))
482   {
483     return (*this)(
484         (*this)(
485           BOOST_ASIO_MOVE_CAST(T)(t),
486           BOOST_ASIO_MOVE_CAST(P0)(p0)),
487         BOOST_ASIO_MOVE_CAST(P1)(p1),
488         BOOST_ASIO_MOVE_CAST(PN)(pn) BOOST_ASIO_ELLIPSIS);
489   }
490 };
491 
492 template <typename T = impl>
493 struct static_instance
494 {
495   static const T instance;
496 };
497 
498 template <typename T>
499 const T static_instance<T>::instance = {};
500 
501 } // namespace asio_prefer_fn
502 namespace boost {
503 namespace asio {
504 namespace {
505 
506 static BOOST_ASIO_CONSTEXPR const asio_prefer_fn::impl&
507   prefer = asio_prefer_fn::static_instance<>::instance;
508 
509 } // namespace
510 
511 #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
512 
513 template <typename T, typename... Properties>
514 struct can_prefer :
515   integral_constant<bool,
516     asio_prefer_fn::call_traits<T, void(Properties...)>::overload
517       != asio_prefer_fn::ill_formed>
518 {
519 };
520 
521 #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
522 
523 template <typename T, typename P0 = void,
524     typename P1 = void, typename P2 = void>
525 struct can_prefer :
526   integral_constant<bool,
527     asio_prefer_fn::call_traits<T, void(P0, P1, P2)>::overload
528       != asio_prefer_fn::ill_formed>
529 {
530 };
531 
532 template <typename T, typename P0, typename P1>
533 struct can_prefer<T, P0, P1> :
534   integral_constant<bool,
535     asio_prefer_fn::call_traits<T, void(P0, P1)>::overload
536       != asio_prefer_fn::ill_formed>
537 {
538 };
539 
540 template <typename T, typename P0>
541 struct can_prefer<T, P0> :
542   integral_constant<bool,
543     asio_prefer_fn::call_traits<T, void(P0)>::overload
544       != asio_prefer_fn::ill_formed>
545 {
546 };
547 
548 template <typename T>
549 struct can_prefer<T> :
550   false_type
551 {
552 };
553 
554 #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
555 
556 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
557 
558 template <typename T, typename BOOST_ASIO_ELLIPSIS Properties>
559 constexpr bool can_prefer_v
560   = can_prefer<T, Properties BOOST_ASIO_ELLIPSIS>::value;
561 
562 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
563 
564 #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
565 
566 template <typename T, typename... Properties>
567 struct is_nothrow_prefer :
568   integral_constant<bool,
569     asio_prefer_fn::call_traits<T, void(Properties...)>::is_noexcept>
570 {
571 };
572 
573 #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
574 
575 template <typename T, typename P0 = void,
576     typename P1 = void, typename P2 = void>
577 struct is_nothrow_prefer :
578   integral_constant<bool,
579     asio_prefer_fn::call_traits<T, void(P0, P1, P2)>::is_noexcept>
580 {
581 };
582 
583 template <typename T, typename P0, typename P1>
584 struct is_nothrow_prefer<T, P0, P1> :
585   integral_constant<bool,
586     asio_prefer_fn::call_traits<T, void(P0, P1)>::is_noexcept>
587 {
588 };
589 
590 template <typename T, typename P0>
591 struct is_nothrow_prefer<T, P0> :
592   integral_constant<bool,
593     asio_prefer_fn::call_traits<T, void(P0)>::is_noexcept>
594 {
595 };
596 
597 template <typename T>
598 struct is_nothrow_prefer<T> :
599   false_type
600 {
601 };
602 
603 #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
604 
605 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
606 
607 template <typename T, typename BOOST_ASIO_ELLIPSIS Properties>
608 constexpr bool is_nothrow_prefer_v
609   = is_nothrow_prefer<T, Properties BOOST_ASIO_ELLIPSIS>::value;
610 
611 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
612 
613 #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
614 
615 template <typename T, typename... Properties>
616 struct prefer_result
617 {
618   typedef typename asio_prefer_fn::call_traits<
619       T, void(Properties...)>::result_type type;
620 };
621 
622 #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
623 
624 template <typename T, typename P0 = void,
625     typename P1 = void, typename P2 = void>
626 struct prefer_result
627 {
628   typedef typename asio_prefer_fn::call_traits<
629       T, void(P0, P1, P2)>::result_type type;
630 };
631 
632 template <typename T, typename P0, typename P1>
633 struct prefer_result<T, P0, P1>
634 {
635   typedef typename asio_prefer_fn::call_traits<
636       T, void(P0, P1)>::result_type type;
637 };
638 
639 template <typename T, typename P0>
640 struct prefer_result<T, P0>
641 {
642   typedef typename asio_prefer_fn::call_traits<
643       T, void(P0)>::result_type type;
644 };
645 
646 template <typename T>
647 struct prefer_result<T>
648 {
649 };
650 
651 #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
652 
653 } // namespace asio
654 } // namespace boost
655 
656 #endif // defined(GENERATING_DOCUMENTATION)
657 
658 #include <boost/asio/detail/pop_options.hpp>
659 
660 #endif // BOOST_ASIO_PREFER_HPP
661