1 //
2 // prefer.hpp
3 // ~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2021 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::conditional;
124 using boost::asio::decay;
125 using boost::asio::declval;
126 using boost::asio::enable_if;
127 using boost::asio::is_applicable_property;
128 using boost::asio::traits::prefer_free;
129 using boost::asio::traits::prefer_member;
130 using boost::asio::traits::require_free;
131 using boost::asio::traits::require_member;
132 using boost::asio::traits::static_require;
133 
134 void prefer();
135 void require();
136 
137 enum overload_type
138 {
139   identity,
140   call_require_member,
141   call_require_free,
142   call_prefer_member,
143   call_prefer_free,
144   two_props,
145   n_props,
146   ill_formed
147 };
148 
149 template <typename Impl, typename T, typename Properties,
150     typename = void, typename = void, typename = void, typename = void,
151     typename = void, typename = void, typename = void>
152 struct call_traits
153 {
154   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
155   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
156   typedef void result_type;
157 };
158 
159 template <typename Impl, typename T, typename Property>
160 struct call_traits<Impl, T, void(Property),
161   typename enable_if<
162     is_applicable_property<
163       typename decay<T>::type,
164       typename decay<Property>::type
165     >::value
166   >::type,
167   typename enable_if<
168     decay<Property>::type::is_preferable
169   >::type,
170   typename enable_if<
171     static_require<T, Property>::is_valid
172   >::type>
173 {
174   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = identity);
175   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
176 
177 #if defined(BOOST_ASIO_HAS_MOVE)
178   typedef BOOST_ASIO_MOVE_ARG(T) result_type;
179 #else // defined(BOOST_ASIO_HAS_MOVE)
180   typedef BOOST_ASIO_MOVE_ARG(typename decay<T>::type) result_type;
181 #endif // defined(BOOST_ASIO_HAS_MOVE)
182 };
183 
184 template <typename Impl, typename T, typename Property>
185 struct call_traits<Impl, T, void(Property),
186   typename enable_if<
187     is_applicable_property<
188       typename decay<T>::type,
189       typename decay<Property>::type
190     >::value
191   >::type,
192   typename enable_if<
193     decay<Property>::type::is_preferable
194   >::type,
195   typename enable_if<
196     !static_require<T, Property>::is_valid
197   >::type,
198   typename enable_if<
199     require_member<typename Impl::template proxy<T>::type, Property>::is_valid
200   >::type> :
201   require_member<typename Impl::template proxy<T>::type, Property>
202 {
203   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_require_member);
204 };
205 
206 template <typename Impl, typename T, typename Property>
207 struct call_traits<Impl, T, void(Property),
208   typename enable_if<
209     is_applicable_property<
210       typename decay<T>::type,
211       typename decay<Property>::type
212     >::value
213   >::type,
214   typename enable_if<
215     decay<Property>::type::is_preferable
216   >::type,
217   typename enable_if<
218     !static_require<T, Property>::is_valid
219   >::type,
220   typename enable_if<
221     !require_member<typename Impl::template proxy<T>::type, Property>::is_valid
222   >::type,
223   typename enable_if<
224     require_free<T, Property>::is_valid
225   >::type> :
226   require_free<T, Property>
227 {
228   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_require_free);
229 };
230 
231 template <typename Impl, typename T, typename Property>
232 struct call_traits<Impl, T, void(Property),
233   typename enable_if<
234     is_applicable_property<
235       typename decay<T>::type,
236       typename decay<Property>::type
237     >::value
238   >::type,
239   typename enable_if<
240     decay<Property>::type::is_preferable
241   >::type,
242   typename enable_if<
243     !static_require<T, Property>::is_valid
244   >::type,
245   typename enable_if<
246     !require_member<typename Impl::template proxy<T>::type, Property>::is_valid
247   >::type,
248   typename enable_if<
249     !require_free<T, Property>::is_valid
250   >::type,
251   typename enable_if<
252     prefer_member<typename Impl::template proxy<T>::type, Property>::is_valid
253   >::type> :
254   prefer_member<typename Impl::template proxy<T>::type, Property>
255 {
256   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_prefer_member);
257 };
258 
259 template <typename Impl, typename T, typename Property>
260 struct call_traits<Impl, T, void(Property),
261   typename enable_if<
262     is_applicable_property<
263       typename decay<T>::type,
264       typename decay<Property>::type
265     >::value
266   >::type,
267   typename enable_if<
268     decay<Property>::type::is_preferable
269   >::type,
270   typename enable_if<
271     !static_require<T, Property>::is_valid
272   >::type,
273   typename enable_if<
274     !require_member<typename Impl::template proxy<T>::type, Property>::is_valid
275   >::type,
276   typename enable_if<
277     !require_free<T, Property>::is_valid
278   >::type,
279   typename enable_if<
280     !prefer_member<typename Impl::template proxy<T>::type, Property>::is_valid
281   >::type,
282   typename enable_if<
283     prefer_free<T, Property>::is_valid
284   >::type> :
285   prefer_free<T, Property>
286 {
287   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_prefer_free);
288 };
289 
290 template <typename Impl, typename T, typename Property>
291 struct call_traits<Impl, T, void(Property),
292   typename enable_if<
293     is_applicable_property<
294       typename decay<T>::type,
295       typename decay<Property>::type
296     >::value
297   >::type,
298   typename enable_if<
299     decay<Property>::type::is_preferable
300   >::type,
301   typename enable_if<
302     !static_require<T, Property>::is_valid
303   >::type,
304   typename enable_if<
305     !require_member<typename Impl::template proxy<T>::type, Property>::is_valid
306   >::type,
307   typename enable_if<
308     !require_free<T, Property>::is_valid
309   >::type,
310   typename enable_if<
311     !prefer_member<typename Impl::template proxy<T>::type, Property>::is_valid
312   >::type,
313   typename enable_if<
314     !prefer_free<T, Property>::is_valid
315   >::type>
316 {
317   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = identity);
318   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
319 
320 #if defined(BOOST_ASIO_HAS_MOVE)
321   typedef BOOST_ASIO_MOVE_ARG(T) result_type;
322 #else // defined(BOOST_ASIO_HAS_MOVE)
323   typedef BOOST_ASIO_MOVE_ARG(typename decay<T>::type) result_type;
324 #endif // defined(BOOST_ASIO_HAS_MOVE)
325 };
326 
327 template <typename Impl, typename T, typename P0, typename P1>
328 struct call_traits<Impl, T, void(P0, P1),
329   typename enable_if<
330     call_traits<Impl, T, void(P0)>::overload != ill_formed
331   >::type,
332   typename enable_if<
333     call_traits<
334       Impl,
335       typename call_traits<Impl, T, void(P0)>::result_type,
336       void(P1)
337     >::overload != ill_formed
338   >::type>
339 {
340   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = two_props);
341 
342   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
343     (
344       call_traits<Impl, T, void(P0)>::is_noexcept
345       &&
346       call_traits<
347         Impl,
348         typename call_traits<Impl, T, void(P0)>::result_type,
349         void(P1)
350       >::is_noexcept
351     ));
352 
353   typedef typename decay<
354     typename call_traits<
355       Impl,
356       typename call_traits<Impl, T, void(P0)>::result_type,
357       void(P1)
358     >::result_type
359   >::type result_type;
360 };
361 
362 template <typename Impl, typename T, typename P0,
363     typename P1, typename BOOST_ASIO_ELLIPSIS PN>
364 struct call_traits<Impl, T, void(P0, P1, PN BOOST_ASIO_ELLIPSIS),
365   typename enable_if<
366     call_traits<Impl, T, void(P0)>::overload != ill_formed
367   >::type,
368   typename enable_if<
369     call_traits<
370       Impl,
371       typename call_traits<Impl, T, void(P0)>::result_type,
372       void(P1, PN BOOST_ASIO_ELLIPSIS)
373     >::overload != ill_formed
374   >::type>
375 {
376   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = n_props);
377 
378   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
379     (
380       call_traits<Impl, T, void(P0)>::is_noexcept
381       &&
382       call_traits<
383         Impl,
384         typename call_traits<Impl, T, void(P0)>::result_type,
385         void(P1, PN BOOST_ASIO_ELLIPSIS)
386       >::is_noexcept
387     ));
388 
389   typedef typename decay<
390     typename call_traits<
391       Impl,
392       typename call_traits<Impl, T, void(P0)>::result_type,
393       void(P1, PN BOOST_ASIO_ELLIPSIS)
394     >::result_type
395   >::type result_type;
396 };
397 
398 struct impl
399 {
400   template <typename T>
401   struct proxy
402   {
403 #if defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) \
404   && defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
405     struct type
406     {
407       template <typename P>
408       auto require(BOOST_ASIO_MOVE_ARG(P) p)
409         noexcept(
410           noexcept(
411             declval<typename conditional<true, T, P>::type>().require(
412               BOOST_ASIO_MOVE_CAST(P)(p))
413           )
414         )
415         -> decltype(
416           declval<typename conditional<true, T, P>::type>().require(
417             BOOST_ASIO_MOVE_CAST(P)(p))
418         );
419 
420       template <typename P>
421       auto prefer(BOOST_ASIO_MOVE_ARG(P) p)
422         noexcept(
423           noexcept(
424             declval<typename conditional<true, T, P>::type>().prefer(
425               BOOST_ASIO_MOVE_CAST(P)(p))
426           )
427         )
428         -> decltype(
429           declval<typename conditional<true, T, P>::type>().prefer(
430             BOOST_ASIO_MOVE_CAST(P)(p))
431         );
432     };
433 #else // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
434       //   && defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
435     typedef T type;
436 #endif // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
437        //   && defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
438   };
439 
440   template <typename T, typename Property>
441   BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if<
442     call_traits<impl, T, void(Property)>::overload == identity,
443     typename call_traits<impl, T, void(Property)>::result_type
444   >::type
operator ()asio_prefer_fn::impl445   operator()(
446       BOOST_ASIO_MOVE_ARG(T) t,
447       BOOST_ASIO_MOVE_ARG(Property)) const
448     BOOST_ASIO_NOEXCEPT_IF((
449       call_traits<impl, T, void(Property)>::is_noexcept))
450   {
451     return BOOST_ASIO_MOVE_CAST(T)(t);
452   }
453 
454   template <typename T, typename Property>
455   BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if<
456     call_traits<impl, T, void(Property)>::overload == call_require_member,
457     typename call_traits<impl, T, void(Property)>::result_type
458   >::type
operator ()asio_prefer_fn::impl459   operator()(
460       BOOST_ASIO_MOVE_ARG(T) t,
461       BOOST_ASIO_MOVE_ARG(Property) p) const
462     BOOST_ASIO_NOEXCEPT_IF((
463       call_traits<impl, T, void(Property)>::is_noexcept))
464   {
465     return BOOST_ASIO_MOVE_CAST(T)(t).require(
466         BOOST_ASIO_MOVE_CAST(Property)(p));
467   }
468 
469   template <typename T, typename Property>
470   BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if<
471     call_traits<impl, T, void(Property)>::overload == call_require_free,
472     typename call_traits<impl, T, void(Property)>::result_type
473   >::type
operator ()asio_prefer_fn::impl474   operator()(
475       BOOST_ASIO_MOVE_ARG(T) t,
476       BOOST_ASIO_MOVE_ARG(Property) p) const
477     BOOST_ASIO_NOEXCEPT_IF((
478       call_traits<impl, T, void(Property)>::is_noexcept))
479   {
480     return require(
481         BOOST_ASIO_MOVE_CAST(T)(t),
482         BOOST_ASIO_MOVE_CAST(Property)(p));
483   }
484 
485   template <typename T, typename Property>
486   BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if<
487     call_traits<impl, T, void(Property)>::overload == call_prefer_member,
488     typename call_traits<impl, T, void(Property)>::result_type
489   >::type
operator ()asio_prefer_fn::impl490   operator()(
491       BOOST_ASIO_MOVE_ARG(T) t,
492       BOOST_ASIO_MOVE_ARG(Property) p) const
493     BOOST_ASIO_NOEXCEPT_IF((
494       call_traits<impl, T, void(Property)>::is_noexcept))
495   {
496     return BOOST_ASIO_MOVE_CAST(T)(t).prefer(
497         BOOST_ASIO_MOVE_CAST(Property)(p));
498   }
499 
500   template <typename T, typename Property>
501   BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if<
502     call_traits<impl, T, void(Property)>::overload == call_prefer_free,
503     typename call_traits<impl, T, void(Property)>::result_type
504   >::type
operator ()asio_prefer_fn::impl505   operator()(
506       BOOST_ASIO_MOVE_ARG(T) t,
507       BOOST_ASIO_MOVE_ARG(Property) p) const
508     BOOST_ASIO_NOEXCEPT_IF((
509       call_traits<impl, T, void(Property)>::is_noexcept))
510   {
511     return prefer(
512         BOOST_ASIO_MOVE_CAST(T)(t),
513         BOOST_ASIO_MOVE_CAST(Property)(p));
514   }
515 
516   template <typename T, typename P0, typename P1>
517   BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if<
518     call_traits<impl, T, void(P0, P1)>::overload == two_props,
519     typename call_traits<impl, T, void(P0, P1)>::result_type
520   >::type
operator ()asio_prefer_fn::impl521   operator()(
522       BOOST_ASIO_MOVE_ARG(T) t,
523       BOOST_ASIO_MOVE_ARG(P0) p0,
524       BOOST_ASIO_MOVE_ARG(P1) p1) const
525     BOOST_ASIO_NOEXCEPT_IF((
526       call_traits<impl, T, void(P0, P1)>::is_noexcept))
527   {
528     return (*this)(
529         (*this)(
530           BOOST_ASIO_MOVE_CAST(T)(t),
531           BOOST_ASIO_MOVE_CAST(P0)(p0)),
532         BOOST_ASIO_MOVE_CAST(P1)(p1));
533   }
534 
535   template <typename T, typename P0, typename P1,
536     typename BOOST_ASIO_ELLIPSIS PN>
537   BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if<
538     call_traits<impl, T,
539       void(P0, P1, PN BOOST_ASIO_ELLIPSIS)>::overload == n_props,
540     typename call_traits<impl, T,
541       void(P0, P1, PN BOOST_ASIO_ELLIPSIS)>::result_type
542   >::type
operator ()asio_prefer_fn::impl543   operator()(
544       BOOST_ASIO_MOVE_ARG(T) t,
545       BOOST_ASIO_MOVE_ARG(P0) p0,
546       BOOST_ASIO_MOVE_ARG(P1) p1,
547       BOOST_ASIO_MOVE_ARG(PN) BOOST_ASIO_ELLIPSIS pn) const
548     BOOST_ASIO_NOEXCEPT_IF((
549       call_traits<impl, T, void(P0, P1, PN BOOST_ASIO_ELLIPSIS)>::is_noexcept))
550   {
551     return (*this)(
552         (*this)(
553           BOOST_ASIO_MOVE_CAST(T)(t),
554           BOOST_ASIO_MOVE_CAST(P0)(p0)),
555         BOOST_ASIO_MOVE_CAST(P1)(p1),
556         BOOST_ASIO_MOVE_CAST(PN)(pn) BOOST_ASIO_ELLIPSIS);
557   }
558 };
559 
560 template <typename T = impl>
561 struct static_instance
562 {
563   static const T instance;
564 };
565 
566 template <typename T>
567 const T static_instance<T>::instance = {};
568 
569 } // namespace asio_prefer_fn
570 namespace boost {
571 namespace asio {
572 namespace {
573 
574 static BOOST_ASIO_CONSTEXPR const asio_prefer_fn::impl&
575   prefer = asio_prefer_fn::static_instance<>::instance;
576 
577 } // namespace
578 
579 typedef asio_prefer_fn::impl prefer_t;
580 
581 #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
582 
583 template <typename T, typename... Properties>
584 struct can_prefer :
585   integral_constant<bool,
586     asio_prefer_fn::call_traits<
587       prefer_t, T, void(Properties...)>::overload
588         != asio_prefer_fn::ill_formed>
589 {
590 };
591 
592 #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
593 
594 template <typename T, typename P0 = void,
595     typename P1 = void, typename P2 = void>
596 struct can_prefer :
597   integral_constant<bool,
598     asio_prefer_fn::call_traits<
599       prefer_t, T, void(P0, P1, P2)>::overload
600         != asio_prefer_fn::ill_formed>
601 {
602 };
603 
604 template <typename T, typename P0, typename P1>
605 struct can_prefer<T, P0, P1> :
606   integral_constant<bool,
607     asio_prefer_fn::call_traits<
608       prefer_t, T, void(P0, P1)>::overload
609         != asio_prefer_fn::ill_formed>
610 {
611 };
612 
613 template <typename T, typename P0>
614 struct can_prefer<T, P0> :
615   integral_constant<bool,
616     asio_prefer_fn::call_traits<
617       prefer_t, T, void(P0)>::overload
618         != asio_prefer_fn::ill_formed>
619 {
620 };
621 
622 template <typename T>
623 struct can_prefer<T> :
624   false_type
625 {
626 };
627 
628 #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
629 
630 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
631 
632 template <typename T, typename BOOST_ASIO_ELLIPSIS Properties>
633 constexpr bool can_prefer_v
634   = can_prefer<T, Properties BOOST_ASIO_ELLIPSIS>::value;
635 
636 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
637 
638 #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
639 
640 template <typename T, typename... Properties>
641 struct is_nothrow_prefer :
642   integral_constant<bool,
643     asio_prefer_fn::call_traits<
644       prefer_t, T, void(Properties...)>::is_noexcept>
645 {
646 };
647 
648 #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
649 
650 template <typename T, typename P0 = void,
651     typename P1 = void, typename P2 = void>
652 struct is_nothrow_prefer :
653   integral_constant<bool,
654     asio_prefer_fn::call_traits<
655       prefer_t, T, void(P0, P1, P2)>::is_noexcept>
656 {
657 };
658 
659 template <typename T, typename P0, typename P1>
660 struct is_nothrow_prefer<T, P0, P1> :
661   integral_constant<bool,
662     asio_prefer_fn::call_traits<
663       prefer_t, T, void(P0, P1)>::is_noexcept>
664 {
665 };
666 
667 template <typename T, typename P0>
668 struct is_nothrow_prefer<T, P0> :
669   integral_constant<bool,
670     asio_prefer_fn::call_traits<
671       prefer_t, T, void(P0)>::is_noexcept>
672 {
673 };
674 
675 template <typename T>
676 struct is_nothrow_prefer<T> :
677   false_type
678 {
679 };
680 
681 #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
682 
683 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
684 
685 template <typename T, typename BOOST_ASIO_ELLIPSIS Properties>
686 constexpr bool is_nothrow_prefer_v
687   = is_nothrow_prefer<T, Properties BOOST_ASIO_ELLIPSIS>::value;
688 
689 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
690 
691 #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
692 
693 template <typename T, typename... Properties>
694 struct prefer_result
695 {
696   typedef typename asio_prefer_fn::call_traits<
697       prefer_t, T, void(Properties...)>::result_type type;
698 };
699 
700 #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
701 
702 template <typename T, typename P0 = void,
703     typename P1 = void, typename P2 = void>
704 struct prefer_result
705 {
706   typedef typename asio_prefer_fn::call_traits<
707       prefer_t, T, void(P0, P1, P2)>::result_type type;
708 };
709 
710 template <typename T, typename P0, typename P1>
711 struct prefer_result<T, P0, P1>
712 {
713   typedef typename asio_prefer_fn::call_traits<
714       prefer_t, T, void(P0, P1)>::result_type type;
715 };
716 
717 template <typename T, typename P0>
718 struct prefer_result<T, P0>
719 {
720   typedef typename asio_prefer_fn::call_traits<
721       prefer_t, T, void(P0)>::result_type type;
722 };
723 
724 template <typename T>
725 struct prefer_result<T>
726 {
727 };
728 
729 #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
730 
731 } // namespace asio
732 } // namespace boost
733 
734 #endif // defined(GENERATING_DOCUMENTATION)
735 
736 #include <boost/asio/detail/pop_options.hpp>
737 
738 #endif // BOOST_ASIO_PREFER_HPP
739