]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Boost.TypeErasure library |
2 | // | |
3 | // Copyright 2011 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_CALLABLE_HPP_INCLUDED | |
14 | #define BOOST_TYPE_ERASURE_CALLABLE_HPP_INCLUDED | |
15 | ||
16 | #include <boost/detail/workaround.hpp> | |
17 | #include <boost/utility/declval.hpp> | |
18 | #include <boost/mpl/vector.hpp> | |
19 | #include <boost/mpl/push_back.hpp> | |
20 | #include <boost/preprocessor/cat.hpp> | |
21 | #include <boost/preprocessor/dec.hpp> | |
22 | #include <boost/preprocessor/iteration/iterate.hpp> | |
23 | #include <boost/preprocessor/repetition/enum.hpp> | |
24 | #include <boost/preprocessor/repetition/enum_params.hpp> | |
25 | #include <boost/preprocessor/repetition/enum_trailing_params.hpp> | |
26 | #include <boost/preprocessor/repetition/enum_binary_params.hpp> | |
27 | #include <boost/preprocessor/repetition/enum_trailing_binary_params.hpp> | |
28 | #include <boost/type_erasure/config.hpp> | |
29 | #include <boost/type_erasure/call.hpp> | |
30 | #include <boost/type_erasure/concept_interface.hpp> | |
31 | #include <boost/type_erasure/rebind_any.hpp> | |
32 | #include <boost/type_erasure/param.hpp> | |
33 | ||
34 | namespace boost { | |
35 | namespace type_erasure { | |
36 | ||
37 | template<class Sig, class F = _self> | |
38 | struct callable; | |
39 | ||
40 | namespace detail { | |
41 | ||
42 | template<class Sig> | |
43 | struct result_of_callable; | |
44 | ||
45 | } | |
46 | ||
47 | #if defined(BOOST_TYPE_ERASURE_DOXYGEN) | |
48 | ||
49 | /** | |
50 | * The @ref callable concept allows an @ref any to hold function objects. | |
51 | * @c Sig is interpreted in the same way as for Boost.Function, except | |
52 | * that the arguments and return type are allowed to be placeholders. | |
53 | * @c F must be a @ref placeholder. | |
54 | * | |
55 | * Multiple instances of @ref callable can be used | |
56 | * simultaneously. Overload resolution works normally. | |
57 | * Note that unlike Boost.Function, @ref callable | |
58 | * does not provide result_type. It does, however, | |
59 | * support @c boost::result_of. | |
60 | */ | |
61 | template<class Sig, class F = _self> | |
62 | struct callable | |
63 | { | |
64 | /** | |
65 | * @c R is the result type of @c Sig and @c T is the argument | |
66 | * types of @c Sig. | |
67 | */ | |
68 | static R apply(F& f, T... arg); | |
69 | }; | |
70 | ||
71 | #elif !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ | |
72 | !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \ | |
73 | !BOOST_WORKAROUND(BOOST_MSVC, == 1800) | |
74 | ||
75 | template<class R, class... T, class F> | |
76 | struct callable<R(T...), F> | |
77 | { | |
78 | static R apply(F& f, T... arg) | |
79 | { | |
80 | return f(std::forward<T>(arg)...); | |
81 | } | |
82 | }; | |
83 | ||
84 | template<class... T, class F> | |
85 | struct callable<void(T...), F> | |
86 | { | |
87 | static void apply(F& f, T... arg) | |
88 | { | |
89 | f(std::forward<T>(arg)...); | |
90 | } | |
91 | }; | |
92 | ||
93 | template<class R, class F, class Base, class Enable, class... T> | |
94 | struct concept_interface<callable<R(T...), F>, Base, F, Enable> | |
95 | : Base | |
96 | { | |
97 | template<class Sig> | |
98 | struct result : | |
99 | ::boost::type_erasure::detail::result_of_callable<Sig> | |
100 | {}; | |
101 | typedef void _boost_type_erasure_is_callable; | |
102 | typedef ::boost::mpl::vector<R> _boost_type_erasure_callable_results; | |
103 | typedef char (&_boost_type_erasure_callable_size)[1]; | |
104 | _boost_type_erasure_callable_size | |
105 | _boost_type_erasure_deduce_callable( | |
106 | typename ::boost::type_erasure::as_param<Base, T>::type...); | |
107 | typename ::boost::type_erasure::rebind_any<Base, R>::type | |
108 | operator()(typename ::boost::type_erasure::as_param<Base, T>::type... arg) | |
109 | { | |
110 | return ::boost::type_erasure::call(callable<R(T...), F>(), *this, | |
111 | ::std::forward<typename ::boost::type_erasure::as_param<Base, T>::type>(arg)...); | |
112 | } | |
113 | }; | |
114 | ||
115 | template<class R, class F, class Base, class Enable, class... T> | |
116 | struct concept_interface<callable<R(T...), const F>, Base, F, Enable> | |
117 | : Base | |
118 | { | |
119 | template<class Sig> | |
120 | struct result : | |
121 | ::boost::type_erasure::detail::result_of_callable<Sig> | |
122 | {}; | |
123 | typedef void _boost_type_erasure_is_callable; | |
124 | typedef ::boost::mpl::vector<R> _boost_type_erasure_callable_results; | |
125 | typedef char (&_boost_type_erasure_callable_size)[1]; | |
126 | _boost_type_erasure_callable_size | |
127 | _boost_type_erasure_deduce_callable( | |
128 | typename ::boost::type_erasure::as_param<Base, T>::type...) const; | |
129 | typename ::boost::type_erasure::rebind_any<Base, R>::type operator()( | |
130 | typename ::boost::type_erasure::as_param<Base, T>::type... arg) const | |
131 | { | |
132 | return ::boost::type_erasure::call(callable<R(T...), const F>(), *this, | |
133 | ::std::forward<typename ::boost::type_erasure::as_param<Base, T>::type>(arg)...); | |
134 | } | |
135 | }; | |
136 | ||
137 | template<class R, class F, class Base, class... T> | |
138 | struct concept_interface< | |
139 | callable<R(T...), F>, | |
140 | Base, | |
141 | F, | |
142 | typename Base::_boost_type_erasure_is_callable | |
143 | > | |
144 | : Base | |
145 | { | |
146 | typedef typename ::boost::mpl::push_back< | |
147 | typename Base::_boost_type_erasure_callable_results, | |
148 | R | |
149 | >::type _boost_type_erasure_callable_results; | |
150 | typedef char (&_boost_type_erasure_callable_size)[ | |
151 | ::boost::mpl::size<_boost_type_erasure_callable_results>::value]; | |
152 | using Base::_boost_type_erasure_deduce_callable; | |
153 | _boost_type_erasure_callable_size | |
154 | _boost_type_erasure_deduce_callable( | |
155 | typename ::boost::type_erasure::as_param<Base, T>::type...); | |
156 | using Base::operator(); | |
157 | typename ::boost::type_erasure::rebind_any<Base, R>::type | |
158 | operator()(typename ::boost::type_erasure::as_param<Base, T>::type... arg) | |
159 | { | |
160 | return ::boost::type_erasure::call(callable<R(T...), F>(), *this, | |
161 | ::std::forward<typename ::boost::type_erasure::as_param<Base, T>::type>(arg)...); | |
162 | } | |
163 | }; | |
164 | ||
165 | template<class R, class F, class Base, class... T> | |
166 | struct concept_interface< | |
167 | callable<R(T...), const F>, | |
168 | Base, | |
169 | F, | |
170 | typename Base::_boost_type_erasure_is_callable | |
171 | > | |
172 | : Base | |
173 | { | |
174 | typedef typename ::boost::mpl::push_back< | |
175 | typename Base::_boost_type_erasure_callable_results, | |
176 | R | |
177 | >::type _boost_type_erasure_callable_results; | |
178 | typedef char (&_boost_type_erasure_callable_size)[ | |
179 | ::boost::mpl::size<_boost_type_erasure_callable_results>::value]; | |
180 | using Base::_boost_type_erasure_deduce_callable; | |
181 | _boost_type_erasure_callable_size | |
182 | _boost_type_erasure_deduce_callable( | |
183 | typename ::boost::type_erasure::as_param<Base, T>::type...) const; | |
184 | using Base::operator(); | |
185 | typename ::boost::type_erasure::rebind_any<Base, R>::type | |
186 | operator()(typename ::boost::type_erasure::as_param<Base, T>::type... arg) const | |
187 | { | |
188 | return ::boost::type_erasure::call(callable<R(T...), const F>(), *this, | |
189 | ::std::forward<typename ::boost::type_erasure::as_param<Base, T>::type>(arg)...); | |
190 | } | |
191 | }; | |
192 | ||
193 | namespace detail { | |
194 | ||
195 | template<class This, class... T> | |
196 | struct result_of_callable<This(T...)> | |
197 | { | |
198 | typedef typename ::boost::mpl::at_c< | |
199 | typename This::_boost_type_erasure_callable_results, | |
200 | sizeof(::boost::declval<This>(). | |
201 | _boost_type_erasure_deduce_callable(::boost::declval<T>()...)) - 1 | |
202 | >::type type; | |
203 | }; | |
204 | ||
205 | } | |
206 | ||
207 | #else | |
208 | ||
209 | /** INTERNAL ONLY */ | |
210 | #define BOOST_PP_FILENAME_1 <boost/type_erasure/callable.hpp> | |
211 | /** INTERNAL ONLY */ | |
212 | #define BOOST_PP_ITERATION_LIMITS (0, BOOST_PP_DEC(BOOST_TYPE_ERASURE_MAX_ARITY)) | |
213 | #include BOOST_PP_ITERATE() | |
214 | ||
215 | #endif | |
216 | ||
217 | } | |
218 | } | |
219 | ||
220 | #endif | |
221 | ||
222 | #else | |
223 | ||
224 | #define N BOOST_PP_ITERATION() | |
225 | #define BOOST_TYPE_ERASURE_DECLVAL(z, n, data) ::boost::declval<BOOST_PP_CAT(T, n)>() | |
226 | ||
227 | #define BOOST_TYPE_ERASURE_REBIND(z, n, data)\ | |
228 | typename ::boost::type_erasure::as_param<Base, BOOST_PP_CAT(T, n)>::type BOOST_PP_CAT(arg, n) | |
229 | ||
230 | #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES | |
231 | #define BOOST_TYPE_ERASURE_FORWARD(z, n, data) BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 1, data), n) | |
232 | #define BOOST_TYPE_ERASURE_FORWARD_REBIND(z, n, data) BOOST_PP_CAT(arg, n) | |
233 | #else | |
234 | #define BOOST_TYPE_ERASURE_FORWARD(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)) | |
235 | #define BOOST_TYPE_ERASURE_FORWARD_REBIND(z, n, data) ::std::forward<typename ::boost::type_erasure::as_param<Base, BOOST_PP_CAT(T, n)>::type>(BOOST_PP_CAT(arg, n)) | |
236 | #endif | |
237 | ||
238 | template<class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T), class F> | |
239 | struct callable<R(BOOST_PP_ENUM_PARAMS(N, T)), F> | |
240 | { | |
241 | static R apply(F& f BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N, T, arg)) | |
242 | { | |
243 | return f(BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_FORWARD, (T, arg))); | |
244 | } | |
245 | }; | |
246 | ||
247 | template<BOOST_PP_ENUM_PARAMS(N, class T) BOOST_PP_COMMA_IF(N) class F> | |
248 | struct callable<void(BOOST_PP_ENUM_PARAMS(N, T)), F> | |
249 | { | |
250 | static void apply(F& f BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N, T, arg)) | |
251 | { | |
252 | f(BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_FORWARD, (T, arg))); | |
253 | } | |
254 | }; | |
255 | ||
256 | template<class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T), class F, class Base, class Enable> | |
257 | struct concept_interface< | |
258 | callable<R(BOOST_PP_ENUM_PARAMS(N, T)), F>, | |
259 | Base, | |
260 | F, | |
261 | Enable | |
262 | > | |
263 | : Base | |
264 | { | |
265 | template<class Sig> | |
266 | struct result : | |
267 | ::boost::type_erasure::detail::result_of_callable<Sig> | |
268 | {}; | |
269 | typedef void _boost_type_erasure_is_callable; | |
270 | typedef ::boost::mpl::vector<R> _boost_type_erasure_callable_results; | |
271 | typedef char (&_boost_type_erasure_callable_size)[1]; | |
272 | _boost_type_erasure_callable_size | |
273 | _boost_type_erasure_deduce_callable( | |
274 | BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_REBIND, ~)); | |
275 | typename ::boost::type_erasure::rebind_any<Base, R>::type | |
276 | operator()(BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_REBIND, ~)) | |
277 | { | |
278 | return ::boost::type_erasure::call( | |
279 | callable<R(BOOST_PP_ENUM_PARAMS(N, T)), F>(), | |
280 | *this BOOST_PP_ENUM_TRAILING(N, BOOST_TYPE_ERASURE_FORWARD_REBIND, ~)); | |
281 | } | |
282 | }; | |
283 | ||
284 | template<class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T), class F, class Base, class Enable> | |
285 | struct concept_interface< | |
286 | callable<R(BOOST_PP_ENUM_PARAMS(N, T)), const F>, | |
287 | Base, | |
288 | F, | |
289 | Enable | |
290 | > | |
291 | : Base | |
292 | { | |
293 | template<class Sig> | |
294 | struct result : | |
295 | ::boost::type_erasure::detail::result_of_callable<Sig> | |
296 | {}; | |
297 | typedef void _boost_type_erasure_is_callable; | |
298 | typedef ::boost::mpl::vector<R> _boost_type_erasure_callable_results; | |
299 | typedef char (&_boost_type_erasure_callable_size)[1]; | |
300 | _boost_type_erasure_callable_size | |
301 | _boost_type_erasure_deduce_callable( | |
302 | BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_REBIND, ~)) const; | |
303 | typename ::boost::type_erasure::rebind_any<Base, R>::type | |
304 | operator()(BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_REBIND, ~)) const | |
305 | { | |
306 | return ::boost::type_erasure::call( | |
307 | callable<R(BOOST_PP_ENUM_PARAMS(N, T)), const F>(), | |
308 | *this BOOST_PP_ENUM_TRAILING(N, BOOST_TYPE_ERASURE_FORWARD_REBIND, ~)); | |
309 | } | |
310 | }; | |
311 | ||
312 | template<class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T), class F, class Base> | |
313 | struct concept_interface< | |
314 | callable<R(BOOST_PP_ENUM_PARAMS(N, T)), F>, | |
315 | Base, | |
316 | F, | |
317 | typename Base::_boost_type_erasure_is_callable | |
318 | > | |
319 | : Base | |
320 | { | |
321 | typedef typename ::boost::mpl::push_back< | |
322 | typename Base::_boost_type_erasure_callable_results, | |
323 | R | |
324 | >::type _boost_type_erasure_callable_results; | |
325 | typedef char (&_boost_type_erasure_callable_size)[ | |
326 | ::boost::mpl::size<_boost_type_erasure_callable_results>::value]; | |
327 | using Base::_boost_type_erasure_deduce_callable; | |
328 | _boost_type_erasure_callable_size | |
329 | _boost_type_erasure_deduce_callable( | |
330 | BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_REBIND, ~)); | |
331 | using Base::operator(); | |
332 | typename ::boost::type_erasure::rebind_any<Base, R>::type | |
333 | operator()(BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_REBIND, ~)) | |
334 | { | |
335 | return ::boost::type_erasure::call( | |
336 | callable<R(BOOST_PP_ENUM_PARAMS(N, T)), F>(), | |
337 | *this BOOST_PP_ENUM_TRAILING(N, BOOST_TYPE_ERASURE_FORWARD_REBIND, ~)); | |
338 | } | |
339 | }; | |
340 | ||
341 | template<class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T), class F, class Base> | |
342 | struct concept_interface< | |
343 | callable<R(BOOST_PP_ENUM_PARAMS(N, T)), const F>, | |
344 | Base, | |
345 | F, | |
346 | typename Base::_boost_type_erasure_is_callable | |
347 | > | |
348 | : Base | |
349 | { | |
350 | typedef typename ::boost::mpl::push_back< | |
351 | typename Base::_boost_type_erasure_callable_results, | |
352 | R | |
353 | >::type _boost_type_erasure_callable_results; | |
354 | typedef char (&_boost_type_erasure_callable_size)[ | |
355 | ::boost::mpl::size<_boost_type_erasure_callable_results>::value]; | |
356 | using Base::_boost_type_erasure_deduce_callable; | |
357 | _boost_type_erasure_callable_size | |
358 | _boost_type_erasure_deduce_callable( | |
359 | BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_REBIND, ~)) const; | |
360 | using Base::operator(); | |
361 | typename ::boost::type_erasure::rebind_any<Base, R>::type | |
362 | operator()(BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_REBIND, ~)) const | |
363 | { | |
364 | return ::boost::type_erasure::call( | |
365 | callable<R(BOOST_PP_ENUM_PARAMS(N, T)), const F>(), | |
366 | *this BOOST_PP_ENUM_TRAILING(N, BOOST_TYPE_ERASURE_FORWARD_REBIND, ~)); | |
367 | } | |
368 | }; | |
369 | ||
370 | namespace detail { | |
371 | ||
372 | template<class This BOOST_PP_ENUM_TRAILING_PARAMS(N, class T)> | |
373 | struct result_of_callable<This(BOOST_PP_ENUM_PARAMS(N, T))> | |
374 | { | |
375 | typedef typename ::boost::mpl::at_c< | |
376 | typename This::_boost_type_erasure_callable_results, | |
377 | sizeof(::boost::declval<This>(). | |
378 | _boost_type_erasure_deduce_callable( | |
379 | BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_DECLVAL, ~))) - 1 | |
380 | >::type type; | |
381 | }; | |
382 | ||
383 | } | |
384 | ||
385 | #undef BOOST_TYPE_ERASURE_DECLVAL | |
386 | #undef BOOST_TYPE_ERASURE_REBIND | |
387 | #undef N | |
388 | ||
389 | #endif |