1 // Boost.TypeErasure library
2 //
3 // Copyright 2011-2012 Steven Watanabe
4 //
5 // Distributed under the Boost Software License Version 1.0. (See
6 // accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 //
9 // $Id$
10
11 #if !defined(BOOST_PP_IS_ITERATING)
12
13 #ifndef BOOST_TYPE_ERASURE_REQUIRE_MATCH_HPP_INCLUDED
14 #define BOOST_TYPE_ERASURE_REQUIRE_MATCH_HPP_INCLUDED
15
16 #include <boost/throw_exception.hpp>
17 #include <boost/mpl/bool.hpp>
18 #include <boost/mpl/and.hpp>
19 #include <boost/type_traits/is_same.hpp>
20 #include <boost/preprocessor/cat.hpp>
21 #include <boost/preprocessor/facilities/intercept.hpp>
22 #include <boost/preprocessor/iteration/iterate.hpp>
23 #include <boost/preprocessor/repetition/repeat.hpp>
24 #include <boost/preprocessor/repetition/enum_params.hpp>
25 #include <boost/preprocessor/repetition/enum_trailing_params.hpp>
26 #include <boost/preprocessor/repetition/enum_trailing_binary_params.hpp>
27 #include <boost/type_erasure/detail/extract_concept.hpp>
28 #include <boost/type_erasure/relaxed.hpp>
29 #include <boost/type_erasure/check_match.hpp>
30 #include <boost/type_erasure/exception.hpp>
31
32 namespace boost {
33 namespace type_erasure {
34
35 #ifndef BOOST_TYPE_ERASURE_DOXYGEN
36 template<class Concept>
37 class binding;
38 #endif
39
40 #ifdef BOOST_TYPE_ERASURE_DOXYGEN
41
42 /**
43 * Checks that the actual types stored in all the @ref any
44 * arguments match the types specified by @c binding. If
45 * they do not match then,
46 * - If @ref relaxed is in @c Concept, throws @ref bad_function_call.
47 * - Otherwise the behavior is undefined.
48 *
49 * If @c binding is not specified, it will be deduced from
50 * the arguments.
51 *
52 * \post \call<code>(binding, f, args...)</code> is valid.
53 */
54 template<class Concept, class Op, class... U>
55 void require_match(const binding<Concept>& binding_arg, const Op& f, U&&... args);
56
57 /**
58 * \overload
59 */
60 template<class Op, class... U>
61 void require_match(const Op& f, U&&... args);
62
63 #else
64
65 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
66
67 namespace detail {
68
69 template<class Concept, class Op, class... U>
require_match_impl(::boost::mpl::true_,const::boost::type_erasure::binding<Concept> & table,const Op & op,U &&...arg)70 void require_match_impl(
71 ::boost::mpl::true_,
72 const ::boost::type_erasure::binding<Concept>& table,
73 const Op& op,
74 U&&... arg)
75 {
76 if(!::boost::type_erasure::check_match(table, op, std::forward<U>(arg)...)) {
77 BOOST_THROW_EXCEPTION(::boost::type_erasure::bad_function_call());
78 }
79 }
80
81 template<class Concept, class Op, class... U>
require_match_impl(::boost::mpl::false_,const::boost::type_erasure::binding<Concept> &,const Op &,U &&...)82 void require_match_impl(
83 ::boost::mpl::false_,
84 const ::boost::type_erasure::binding<Concept>&,
85 const Op&,
86 U&&...)
87 {}
88
89 template<class Op, class... U>
require_match_impl(::boost::mpl::true_,const Op & op,U &&...arg)90 void require_match_impl(
91 ::boost::mpl::true_,
92 const Op& op,
93 U&&... arg)
94 {
95 if(!::boost::type_erasure::check_match(op, ::std::forward<U>(arg)...)) {
96 BOOST_THROW_EXCEPTION(::boost::type_erasure::bad_function_call());
97 }
98 }
99
100 template<class Op, class... U>
require_match_impl(::boost::mpl::false_,const Op &,U &&...)101 void require_match_impl(
102 ::boost::mpl::false_,
103 const Op&,
104 U&&...)
105 {}
106
107 }
108
109 template<class Concept, class Op, class... U>
require_match(const::boost::type_erasure::binding<Concept> & table,const Op & op,U &&...arg)110 void require_match(
111 const ::boost::type_erasure::binding<Concept>& table,
112 const Op& op,
113 U&&... arg)
114 {
115 ::boost::type_erasure::is_relaxed<Concept> cond;
116 ::boost::type_erasure::detail::require_match_impl(cond, table, op, ::std::forward<U>(arg)...);
117 }
118
119 #ifndef BOOST_TYPE_ERASURE_USE_MP11
120
121 template<class Op, class... U>
require_match(const Op & op,U &&...arg)122 void require_match(
123 const Op& op,
124 U&&... arg)
125 {
126 ::boost::type_erasure::is_relaxed<
127 typename ::boost::type_erasure::detail::extract_concept<
128 typename ::boost::type_erasure::detail::get_signature<Op>::type,
129 U...>::type
130 > cond;
131 ::boost::type_erasure::detail::require_match_impl(cond, op, ::std::forward<U>(arg)...);
132 }
133
134 #else
135
136 template<class Op, class... U>
require_match(const Op & op,U &&...arg)137 void require_match(
138 const Op& op,
139 U&&... arg)
140 {
141 ::boost::type_erasure::is_relaxed<
142 ::boost::type_erasure::detail::extract_concept_t<
143 ::boost::type_erasure::detail::get_args_t<
144 typename ::boost::type_erasure::detail::get_signature<Op>::type
145 >,
146 ::boost::mp11::mp_list< ::boost::remove_reference_t<U>...> >
147 > cond;
148 ::boost::type_erasure::detail::require_match_impl(cond, op, ::std::forward<U>(arg)...);
149 }
150
151 #endif
152
153 #else
154
155 #define BOOST_PP_FILENAME_1 <boost/type_erasure/require_match.hpp>
156 #define BOOST_PP_ITERATION_LIMITS (0, BOOST_TYPE_ERASURE_MAX_ARITY)
157 #include BOOST_PP_ITERATE()
158
159 #endif
160
161 #endif
162
163 }
164 }
165
166 #endif
167
168 #else
169
170 #define N BOOST_PP_ITERATION()
171
172 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
173 #define RREF &
174 #define BOOST_TYPE_ERASURE_FORWARD_ARGS(N, X, x) BOOST_PP_ENUM_TRAILING_PARAMS(N, x)
175 #else
176 #define RREF &&
177 #define BOOST_TYPE_ERASURE_FORWARD_ARGS_I(z, n, data) std::forward<BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 0, data), n)>(BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 1, data), n))
178 #define BOOST_TYPE_ERASURE_FORWARD_ARGS(N, X, x) BOOST_PP_ENUM_TRAILING(N, BOOST_TYPE_ERASURE_FORWARD_ARGS_I, (X, x))
179 #endif
180
181 namespace detail {
182
183 template<
184 class Concept,
185 class Op
186 BOOST_PP_ENUM_TRAILING_PARAMS(N, class U)
187 >
require_match_impl(::boost::mpl::true_,const::boost::type_erasure::binding<Concept> & table,const Op & op BOOST_PP_ENUM_TRAILING_BINARY_PARAMS (N,U,RREF arg))188 void require_match_impl(
189 ::boost::mpl::true_,
190 const ::boost::type_erasure::binding<Concept>& table,
191 const Op& op
192 BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N, U, RREF arg))
193 {
194 if(!::boost::type_erasure::check_match
195 (table, op BOOST_TYPE_ERASURE_FORWARD_ARGS(N, U, arg))) {
196 BOOST_THROW_EXCEPTION(::boost::type_erasure::bad_function_call());
197 }
198 }
199
200 template<
201 class Concept,
202 class Op
203 BOOST_PP_ENUM_TRAILING_PARAMS(N, class U)
204 >
require_match_impl(::boost::mpl::false_,const::boost::type_erasure::binding<Concept> &,const Op & BOOST_PP_ENUM_TRAILING_BINARY_PARAMS (N,U,RREF BOOST_PP_INTERCEPT))205 void require_match_impl(
206 ::boost::mpl::false_,
207 const ::boost::type_erasure::binding<Concept>&,
208 const Op&
209 BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N, U, RREF BOOST_PP_INTERCEPT))
210 {}
211
212 #if N != 0
213
214 template<
215 class Op
216 BOOST_PP_ENUM_TRAILING_PARAMS(N, class U)
217 >
require_match_impl(::boost::mpl::true_,const Op & op BOOST_PP_ENUM_TRAILING_BINARY_PARAMS (N,U,RREF arg))218 void require_match_impl(
219 ::boost::mpl::true_,
220 const Op& op
221 BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N, U, RREF arg))
222 {
223 if(!::boost::type_erasure::check_match
224 (op BOOST_TYPE_ERASURE_FORWARD_ARGS(N, U, arg))) {
225 BOOST_THROW_EXCEPTION(::boost::type_erasure::bad_function_call());
226 }
227 }
228
229 template<
230 class Op
231 BOOST_PP_ENUM_TRAILING_PARAMS(N, class U)
232 >
require_match_impl(::boost::mpl::false_,const Op & BOOST_PP_ENUM_TRAILING_BINARY_PARAMS (N,U,RREF BOOST_PP_INTERCEPT))233 void require_match_impl(
234 ::boost::mpl::false_,
235 const Op&
236 BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N, U, RREF BOOST_PP_INTERCEPT))
237 {}
238
239 #endif
240
241 }
242
243 template<
244 class Concept,
245 class Op
246 BOOST_PP_ENUM_TRAILING_PARAMS(N, class U)
247 >
require_match(const::boost::type_erasure::binding<Concept> & table,const Op & op BOOST_PP_ENUM_TRAILING_BINARY_PARAMS (N,U,RREF arg))248 void require_match(
249 const ::boost::type_erasure::binding<Concept>& table,
250 const Op& op
251 BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N, U, RREF arg))
252 {
253 ::boost::type_erasure::is_relaxed<Concept> cond;
254 ::boost::type_erasure::detail::require_match_impl
255 (cond, table, op BOOST_TYPE_ERASURE_FORWARD_ARGS(N, U, arg));
256 }
257
258 #if N != 0
259
260 template<
261 class Op
262 BOOST_PP_ENUM_TRAILING_PARAMS(N, class U)
263 >
require_match(const Op & op BOOST_PP_ENUM_TRAILING_BINARY_PARAMS (N,U,RREF arg))264 void require_match(
265 const Op& op
266 BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N, U, RREF arg))
267 {
268 ::boost::type_erasure::is_relaxed<
269 typename ::boost::type_erasure::detail::BOOST_PP_CAT(do_extract_concept, N)<
270 typename ::boost::type_erasure::detail::get_signature<Op>::type,
271 BOOST_PP_ENUM_PARAMS(N, U)>::type
272 > cond;
273 ::boost::type_erasure::detail::require_match_impl
274 (cond, op BOOST_TYPE_ERASURE_FORWARD_ARGS(N, U, arg));
275 }
276
277 #endif
278
279 #undef RREF
280 #undef BOOST_TYPE_ERASURE_FORWARD_ARGS
281 #undef BOOST_TYPE_ERASURE_FORWARD_ARGS_I
282 #undef N
283
284 #endif
285