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 {
applyboost::type_erasure::callable78     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 {
applyboost::type_erasure::callable87     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
operator ()boost::type_erasure::concept_interface108     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;
operator ()boost::type_erasure::concept_interface129     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
operator ()boost::type_erasure::concept_interface158     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
operator ()boost::type_erasure::concept_interface186     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 {
applycallable241     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 {
applycallable250     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
390