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