1 //
2 // detail/handler_type_requirements.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2015 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 ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_HPP
12 #define ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_HPP
13 
14 
15 #include "asio/detail/config.hpp"
16 
17 // Older versions of gcc have difficulty compiling the sizeof expressions where
18 // we test the handler type requirements. We'll disable checking of handler type
19 // requirements for those compilers, but otherwise enable it by default.
20 #if !defined(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)
21 # if !defined(__GNUC__) || (__GNUC__ >= 4)
22 #  define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS 1
23 # endif // !defined(__GNUC__) || (__GNUC__ >= 4)
24 #endif // !defined(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)
25 
26 // With C++0x we can use a combination of enhanced SFINAE and static_assert to
27 // generate better template error messages. As this technique is not yet widely
28 // portable, we'll only enable it for tested compilers.
29 #if !defined(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
30 # if defined(__GNUC__)
31 #  if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
32 #   if defined(__GXX_EXPERIMENTAL_CXX0X__)
33 #    define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1
34 #   endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
35 #  endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
36 # endif // defined(__GNUC__)
37 #  if __has_feature(__cxx_static_assert__)
38 #   define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1
39 #  endif // __has_feature(cxx_static_assert)
40 #endif // !defined(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)
41 
42 #if defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
43 # include "asio/handler_type.hpp"
44 #endif // defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
45 
46 // Newer gcc needs special treatment to suppress unused typedef warnings.
47 #if defined(__GNUC__)
48 # if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)
49 #  define ASIO_UNUSED_TYPEDEF __attribute__((__unused__))
50 # endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)
51 #endif // defined(__GNUC__)
52 #if !defined(ASIO_UNUSED_TYPEDEF)
53 # define ASIO_UNUSED_TYPEDEF
54 #endif // !defined(ASIO_UNUSED_TYPEDEF)
55 
56 namespace asio {
57 namespace detail {
58 
59 #if defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
60 
61 # if defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
62 
63 template <typename Handler>
64 auto zero_arg_handler_test(Handler h, void*)
65   -> decltype(
66     sizeof(Handler(static_cast<const Handler&>(h))),
67     ((h)()),
68     char(0));
69 
70 template <typename Handler>
71 char (&zero_arg_handler_test(Handler, ...))[2];
72 
73 template <typename Handler, typename Arg1>
74 auto one_arg_handler_test(Handler h, Arg1* a1)
75   -> decltype(
76     sizeof(Handler(static_cast<const Handler&>(h))),
77     ((h)(*a1)),
78     char(0));
79 
80 template <typename Handler>
81 char (&one_arg_handler_test(Handler h, ...))[2];
82 
83 template <typename Handler, typename Arg1, typename Arg2>
84 auto two_arg_handler_test(Handler h, Arg1* a1, Arg2* a2)
85   -> decltype(
86     sizeof(Handler(static_cast<const Handler&>(h))),
87     ((h)(*a1, *a2)),
88     char(0));
89 
90 template <typename Handler>
91 char (&two_arg_handler_test(Handler, ...))[2];
92 
93 #  define ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg)       static_assert(expr, msg);
94 
95 # else // defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
96 
97 #  define ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg)
98 
99 # endif // defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
100 
101 template <typename T> T& lvref();
102 template <typename T> T& lvref(T);
103 template <typename T> const T& clvref();
104 template <typename T> const T& clvref(T);
105 template <typename T> char argbyv(T);
106 
107 template <int>
108 struct handler_type_requirements
109 {
110 };
111 
112 #define ASIO_COMPLETION_HANDLER_CHECK(      handler_type, handler)       typedef ASIO_HANDLER_TYPE(handler_type,        void()) asio_true_handler_type;       ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(        sizeof(asio::detail::zero_arg_handler_test(            asio::detail::clvref<              asio_true_handler_type>(), 0)) == 1,        "CompletionHandler type requirements not met")       typedef asio::detail::handler_type_requirements<        sizeof(          asio::detail::argbyv(            asio::detail::clvref<              asio_true_handler_type>())) +        sizeof(          asio::detail::lvref<            asio_true_handler_type>()(),          char(0))> ASIO_UNUSED_TYPEDEF
113 
114 #define ASIO_READ_HANDLER_CHECK(      handler_type, handler)       typedef ASIO_HANDLER_TYPE(handler_type,        void(asio::error_code, std::size_t))      asio_true_handler_type;       ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(        sizeof(asio::detail::two_arg_handler_test(            asio::detail::clvref<              asio_true_handler_type>(),            static_cast<const asio::error_code*>(0),            static_cast<const std::size_t*>(0))) == 1,        "ReadHandler type requirements not met")       typedef asio::detail::handler_type_requirements<        sizeof(          asio::detail::argbyv(            asio::detail::clvref<              asio_true_handler_type>())) +        sizeof(          asio::detail::lvref<            asio_true_handler_type>()(              asio::detail::lvref<const asio::error_code>(),              asio::detail::lvref<const std::size_t>()),          char(0))> ASIO_UNUSED_TYPEDEF
115 
116 
117 #define ASIO_WRITE_HANDLER_CHECK(      handler_type, handler)       typedef ASIO_HANDLER_TYPE(handler_type,        void(asio::error_code, std::size_t))      asio_true_handler_type;       ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(        sizeof(asio::detail::two_arg_handler_test(            asio::detail::clvref<              asio_true_handler_type>(),            static_cast<const asio::error_code*>(0),            static_cast<const std::size_t*>(0))) == 1,        "WriteHandler type requirements not met")       typedef asio::detail::handler_type_requirements<        sizeof(          asio::detail::argbyv(            asio::detail::clvref<              asio_true_handler_type>())) +        sizeof(          asio::detail::lvref<            asio_true_handler_type>()(              asio::detail::lvref<const asio::error_code>(),              asio::detail::lvref<const std::size_t>()),          char(0))> ASIO_UNUSED_TYPEDEF
118 
119 #define ASIO_ACCEPT_HANDLER_CHECK(      handler_type, handler)       typedef ASIO_HANDLER_TYPE(handler_type,        void(asio::error_code))      asio_true_handler_type;       ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(        sizeof(asio::detail::one_arg_handler_test(            asio::detail::clvref<              asio_true_handler_type>(),            static_cast<const asio::error_code*>(0))) == 1,        "AcceptHandler type requirements not met")       typedef asio::detail::handler_type_requirements<        sizeof(          asio::detail::argbyv(            asio::detail::clvref<              asio_true_handler_type>())) +        sizeof(          asio::detail::lvref<            asio_true_handler_type>()(              asio::detail::lvref<const asio::error_code>()),          char(0))> ASIO_UNUSED_TYPEDEF
120 
121 #define ASIO_CONNECT_HANDLER_CHECK(      handler_type, handler)       typedef ASIO_HANDLER_TYPE(handler_type,        void(asio::error_code))      asio_true_handler_type;       ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(        sizeof(asio::detail::one_arg_handler_test(            asio::detail::clvref<              asio_true_handler_type>(),            static_cast<const asio::error_code*>(0))) == 1,        "ConnectHandler type requirements not met")       typedef asio::detail::handler_type_requirements<        sizeof(          asio::detail::argbyv(            asio::detail::clvref<              asio_true_handler_type>())) +        sizeof(          asio::detail::lvref<            asio_true_handler_type>()(              asio::detail::lvref<const asio::error_code>()),          char(0))> ASIO_UNUSED_TYPEDEF
122 
123 #define ASIO_COMPOSED_CONNECT_HANDLER_CHECK(      handler_type, handler, iter_type)       typedef ASIO_HANDLER_TYPE(handler_type,        void(asio::error_code, iter_type))      asio_true_handler_type;       ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(        sizeof(asio::detail::two_arg_handler_test(            asio::detail::clvref<              asio_true_handler_type>(),            static_cast<const asio::error_code*>(0),            static_cast<const iter_type*>(0))) == 1,        "ComposedConnectHandler type requirements not met")       typedef asio::detail::handler_type_requirements<        sizeof(          asio::detail::argbyv(            asio::detail::clvref<              asio_true_handler_type>())) +        sizeof(          asio::detail::lvref<            asio_true_handler_type>()(              asio::detail::lvref<const asio::error_code>(),              asio::detail::lvref<const iter_type>()),          char(0))> ASIO_UNUSED_TYPEDEF
124 
125 #define ASIO_RESOLVE_HANDLER_CHECK(      handler_type, handler, iter_type)       typedef ASIO_HANDLER_TYPE(handler_type,        void(asio::error_code, iter_type))      asio_true_handler_type;       ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(        sizeof(asio::detail::two_arg_handler_test(            asio::detail::clvref<              asio_true_handler_type>(),            static_cast<const asio::error_code*>(0),            static_cast<const iter_type*>(0))) == 1,        "ResolveHandler type requirements not met")       typedef asio::detail::handler_type_requirements<        sizeof(          asio::detail::argbyv(            asio::detail::clvref<              asio_true_handler_type>())) +        sizeof(          asio::detail::lvref<            asio_true_handler_type>()(              asio::detail::lvref<const asio::error_code>(),              asio::detail::lvref<const iter_type>()),          char(0))> ASIO_UNUSED_TYPEDEF
126 
127 #define ASIO_WAIT_HANDLER_CHECK(      handler_type, handler)       typedef ASIO_HANDLER_TYPE(handler_type,        void(asio::error_code))      asio_true_handler_type;       ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(        sizeof(asio::detail::one_arg_handler_test(            asio::detail::clvref<              asio_true_handler_type>(),            static_cast<const asio::error_code*>(0))) == 1,        "WaitHandler type requirements not met")       typedef asio::detail::handler_type_requirements<        sizeof(          asio::detail::argbyv(            asio::detail::clvref<              asio_true_handler_type>())) +        sizeof(          asio::detail::lvref<            asio_true_handler_type>()(              asio::detail::lvref<const asio::error_code>()),          char(0))> ASIO_UNUSED_TYPEDEF
128 
129 #define ASIO_SIGNAL_HANDLER_CHECK(      handler_type, handler)       typedef ASIO_HANDLER_TYPE(handler_type,        void(asio::error_code, int))      asio_true_handler_type;       ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(        sizeof(asio::detail::two_arg_handler_test(            asio::detail::clvref<              asio_true_handler_type>(),            static_cast<const asio::error_code*>(0),            static_cast<const int*>(0))) == 1,        "SignalHandler type requirements not met")       typedef asio::detail::handler_type_requirements<        sizeof(          asio::detail::argbyv(            asio::detail::clvref<              asio_true_handler_type>())) +        sizeof(          asio::detail::lvref<            asio_true_handler_type>()(              asio::detail::lvref<const asio::error_code>(),              asio::detail::lvref<const int>()),          char(0))> ASIO_UNUSED_TYPEDEF
130 
131 #define ASIO_HANDSHAKE_HANDLER_CHECK(      handler_type, handler)       typedef ASIO_HANDLER_TYPE(handler_type,        void(asio::error_code))      asio_true_handler_type;       ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(        sizeof(asio::detail::one_arg_handler_test(            asio::detail::clvref<              asio_true_handler_type>(),            static_cast<const asio::error_code*>(0))) == 1,        "HandshakeHandler type requirements not met")       typedef asio::detail::handler_type_requirements<        sizeof(          asio::detail::argbyv(            asio::detail::clvref<              asio_true_handler_type>())) +        sizeof(          asio::detail::lvref<            asio_true_handler_type>()(              asio::detail::lvref<const asio::error_code>()),          char(0))> ASIO_UNUSED_TYPEDEF
132 
133 #define ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK(      handler_type, handler)       typedef ASIO_HANDLER_TYPE(handler_type,        void(asio::error_code, std::size_t))      asio_true_handler_type;       ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(        sizeof(asio::detail::two_arg_handler_test(            asio::detail::clvref<              asio_true_handler_type>(),            static_cast<const asio::error_code*>(0),            static_cast<const std::size_t*>(0))) == 1,        "BufferedHandshakeHandler type requirements not met")       typedef asio::detail::handler_type_requirements<        sizeof(          asio::detail::argbyv(            asio::detail::clvref<              asio_true_handler_type>())) +        sizeof(          asio::detail::lvref<            asio_true_handler_type>()(            asio::detail::lvref<const asio::error_code>(),            asio::detail::lvref<const std::size_t>()),          char(0))> ASIO_UNUSED_TYPEDEF
134 
135 #define ASIO_SHUTDOWN_HANDLER_CHECK(      handler_type, handler)       typedef ASIO_HANDLER_TYPE(handler_type,        void(asio::error_code))      asio_true_handler_type;       ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(        sizeof(asio::detail::one_arg_handler_test(            asio::detail::clvref<              asio_true_handler_type>(),            static_cast<const asio::error_code*>(0))) == 1,        "ShutdownHandler type requirements not met")       typedef asio::detail::handler_type_requirements<        sizeof(          asio::detail::argbyv(            asio::detail::clvref<              asio_true_handler_type>())) +        sizeof(          asio::detail::lvref<            asio_true_handler_type>()(              asio::detail::lvref<const asio::error_code>()),          char(0))> ASIO_UNUSED_TYPEDEF
136 
137 #else // !defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
138 
139 #define ASIO_COMPLETION_HANDLER_CHECK(      handler_type, handler)    typedef int ASIO_UNUSED_TYPEDEF
140 
141 #define ASIO_READ_HANDLER_CHECK(      handler_type, handler)    typedef int ASIO_UNUSED_TYPEDEF
142 
143 #define ASIO_WRITE_HANDLER_CHECK(      handler_type, handler)    typedef int ASIO_UNUSED_TYPEDEF
144 
145 #define ASIO_ACCEPT_HANDLER_CHECK(      handler_type, handler)    typedef int ASIO_UNUSED_TYPEDEF
146 
147 #define ASIO_CONNECT_HANDLER_CHECK(      handler_type, handler)    typedef int ASIO_UNUSED_TYPEDEF
148 
149 #define ASIO_COMPOSED_CONNECT_HANDLER_CHECK(      handler_type, handler, iter_type)    typedef int ASIO_UNUSED_TYPEDEF
150 
151 #define ASIO_RESOLVE_HANDLER_CHECK(      handler_type, handler, iter_type)    typedef int ASIO_UNUSED_TYPEDEF
152 
153 #define ASIO_WAIT_HANDLER_CHECK(      handler_type, handler)    typedef int ASIO_UNUSED_TYPEDEF
154 
155 #define ASIO_SIGNAL_HANDLER_CHECK(      handler_type, handler)    typedef int ASIO_UNUSED_TYPEDEF
156 
157 #define ASIO_HANDSHAKE_HANDLER_CHECK(      handler_type, handler)    typedef int ASIO_UNUSED_TYPEDEF
158 
159 #define ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK(      handler_type, handler)    typedef int ASIO_UNUSED_TYPEDEF
160 
161 #define ASIO_SHUTDOWN_HANDLER_CHECK(      handler_type, handler)    typedef int ASIO_UNUSED_TYPEDEF
162 
163 #endif // !defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
164 
165 } // namespace detail
166 } // namespace asio
167 
168 #endif // ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_HPP
169