1 // Boost.TypeErasure library
2 //
3 // Copyright 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 #ifndef BOOST_TYPE_ERASURE_FREE_HPP_INCLUDED
12 #define BOOST_TYPE_ERASURE_FREE_HPP_INCLUDED
13 
14 #include <boost/detail/workaround.hpp>
15 #include <boost/preprocessor/repetition/enum.hpp>
16 #include <boost/preprocessor/repetition/enum_trailing.hpp>
17 #include <boost/preprocessor/repetition/enum_params.hpp>
18 #include <boost/preprocessor/repetition/enum_shifted_params.hpp>
19 #include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>
20 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
21 #include <boost/preprocessor/cat.hpp>
22 #include <boost/preprocessor/control/if.hpp>
23 #include <boost/preprocessor/punctuation/is_begin_parens.hpp>
24 #include <boost/vmd/is_empty.hpp>
25 #include <boost/type_traits/remove_reference.hpp>
26 #include <boost/type_traits/remove_cv.hpp>
27 #include <boost/mpl/eval_if.hpp>
28 #include <boost/mpl/identity.hpp>
29 #include <boost/mpl/int.hpp>
bad_function_call()30 #include <boost/mpl/next.hpp>
31 #include <boost/type_erasure/detail/macro.hpp>
32 #include <boost/type_erasure/detail/const.hpp>
33 #include <boost/type_erasure/config.hpp>
34 #include <boost/type_erasure/derived.hpp>
35 #include <boost/type_erasure/rebind_any.hpp>
36 #include <boost/type_erasure/param.hpp>
37 #include <boost/type_erasure/is_placeholder.hpp>
38 #include <boost/type_erasure/call.hpp>
39 #include <boost/type_erasure/concept_interface.hpp>
40 
41 #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || \
42     defined(BOOST_NO_CXX11_RVALUE_REFERENCES) || \
43     defined(BOOST_TYPE_ERASURE_DOXYGEN) || \
44     BOOST_WORKAROUND(BOOST_MSVC, == 1800)
45 
46 namespace boost {
47 namespace type_erasure {
48 namespace detail {
49 
50 template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(BOOST_TYPE_ERASURE_MAX_ARITY, class T, void)>
51 struct first_placeholder {
52     typedef typename ::boost::mpl::eval_if<is_placeholder<T0>,
53         ::boost::mpl::identity<T0>,
54         first_placeholder<BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_TYPE_ERASURE_MAX_ARITY, T)>
55     >::type type;
56 };
57 
58 template<>
59 struct first_placeholder<> {};
60 
61 template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(BOOST_TYPE_ERASURE_MAX_ARITY, class T, void)>
62 struct first_placeholder_index :
63     ::boost::mpl::eval_if<is_placeholder<T0>,
64         ::boost::mpl::int_<0>,
65         ::boost::mpl::next<first_placeholder_index<BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_TYPE_ERASURE_MAX_ARITY, T)> >
66     >::type
67 {};
68 
69 }
70 }
71 }
72 
73 /** INTERNAL ONLY */
74 #define BOOST_TYPE_ERASURE_FREE_QUALIFIED_ID(seq, N) \
75     BOOST_TYPE_ERASURE_QUALIFIED_NAME(seq)<R(BOOST_PP_ENUM_PARAMS(N, T))>
76 
77 /** INTERNAL ONLY */
78 #define BOOST_TYPE_ERASURE_FREE_UNQUALIFIED_PARAM_TYPE(z, n, data) \
79     typename ::boost::remove_cv<typename ::boost::remove_reference<BOOST_PP_CAT(T, n)>::type>::type
80 
81 /** INTERNAL ONLY */
82 #define BOOST_TYPE_ERASURE_FREE_PARAM_TYPE(z, n, data)                      \
83     typename ::boost::mpl::eval_if_c<(_boost_type_erasure_free_p_idx::value == n), \
84         ::boost::type_erasure::detail::maybe_const_this_param<BOOST_PP_CAT(T, n), Base>,    \
85         ::boost::type_erasure::as_param<Base, BOOST_PP_CAT(T, n)>           \
86     >::type BOOST_PP_CAT(t, n)
87 
88 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
89 
90 /** INTERNAL ONLY */
91 #define BOOST_TYPE_ERASURE_FREE_FORWARD_I(z, n, data) ::std::forward<BOOST_PP_CAT(T, n)>(BOOST_PP_CAT(t, n))
92 /** INTERNAL ONLY */
93 #define BOOST_TYPE_ERASURE_FREE_FORWARD(n) BOOST_PP_ENUM(n, BOOST_TYPE_ERASURE_FREE_FORWARD_I, ~)
94 /** INTERNAL ONLY */
95 #define BOOST_TYPE_ERASURE_FREE_FORWARD_PARAM_I(z, n, data) \
96     ::std::forward<typename ::boost::mpl::eval_if_c<(_boost_type_erasure_free_p_idx::value == n), \
97         ::boost::type_erasure::detail::maybe_const_this_param<BOOST_PP_CAT(T, n), Base>,    \
98         ::boost::type_erasure::as_param<Base, BOOST_PP_CAT(T, n)>           \
99     >::type>(BOOST_PP_CAT(t, n))
100 
101 #else
102 
103 #define BOOST_TYPE_ERASURE_FREE_FORWARD(n) BOOST_PP_ENUM_PARAMS(n, t)
104 #define BOOST_TYPE_ERASURE_FREE_FORWARD_PARAM_I(z, n, data) BOOST_PP_CAT(t, n)
105 
106 #endif
107 
108 /** INTERNAL ONLY */
109 #define BOOST_TYPE_ERASURE_FREE_II(qual_name, concept_name, function_name, N)  \
110     BOOST_TYPE_ERASURE_OPEN_NAMESPACE(qual_name)                        \
111                                                                         \
112     template<class Sig>                                                 \
113     struct concept_name;                                                \
114                                                                         \
115     template<class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T)>         \
116     struct concept_name<R(BOOST_PP_ENUM_PARAMS(N, T))> {                \
117         static R apply(BOOST_PP_ENUM_BINARY_PARAMS(N, T, t))            \
118         { return function_name(BOOST_TYPE_ERASURE_FREE_FORWARD(N)); }   \
119     };                                                                  \
120                                                                         \
121     template<BOOST_PP_ENUM_PARAMS(N, class T)>                          \
122     struct concept_name<void(BOOST_PP_ENUM_PARAMS(N, T))> {             \
123         static void apply(BOOST_PP_ENUM_BINARY_PARAMS(N, T, t))         \
124         { function_name(BOOST_TYPE_ERASURE_FREE_FORWARD(N)); }          \
125     };                                                                  \
126                                                                         \
127     BOOST_TYPE_ERASURE_CLOSE_NAMESPACE(qual_name)                       \
128                                                                         \
129     namespace boost {                                                   \
130     namespace type_erasure {                                            \
131                                                                         \
132     template<class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T), class Base> \
133     struct concept_interface<                                           \
134         BOOST_TYPE_ERASURE_FREE_QUALIFIED_ID(qual_name, N),             \
135         Base,                                                           \
136         typename ::boost::type_erasure::detail::first_placeholder<      \
137             BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_FREE_UNQUALIFIED_PARAM_TYPE, ~)>::type  \
138     > : Base {                                                          \
139         typedef typename ::boost::type_erasure::detail::first_placeholder_index<    \
140             BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_FREE_UNQUALIFIED_PARAM_TYPE, ~)>::type  \
141             _boost_type_erasure_free_p_idx;                             \
142         friend typename ::boost::type_erasure::rebind_any<Base, R>::type function_name(  \
143             BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_FREE_PARAM_TYPE, ~))    \
144         {                                                               \
145             return ::boost::type_erasure::call(                         \
146                 BOOST_TYPE_ERASURE_FREE_QUALIFIED_ID(qual_name, N)()    \
147                 BOOST_PP_ENUM_TRAILING(N, BOOST_TYPE_ERASURE_FREE_FORWARD_PARAM_I, ~)); \
148         }                                                               \
149     };                                                                  \
150                                                                         \
151     }                                                                   \
152     }
153 
154 /** INTERNAL ONLY */
155 #define BOOST_TYPE_ERASURE_FREE_I(namespace_name, concept_name, function_name, N)\
156     BOOST_TYPE_ERASURE_FREE_II(namespace_name, concept_name, function_name, N)
157 
158 #ifdef BOOST_TYPE_ERASURE_DOXYGEN
159 
160 /**
161  * \brief Defines a primitive concept for a free function.
162  *
163  * \param concept_name is the name of the concept to declare.
164  *        If it is omitted it defaults to <code>has_ ## function_name</code>
165  * \param function_name is the name of the function.
166  *
167  * The declaration of the concept is
168  * \code
169  * template<class Sig>
170  * struct concept_name;
171  * \endcode
172  * where Sig is a function type giving the
173  * signature of the function.
174  *
175  * This macro can only be used at namespace scope.
176  *
177  * Example:
178  *
179  * \code
180  * BOOST_TYPE_ERASURE_FREE(to_string)
181  * typedef has_to_string<std::string(_self const&)> to_string_concept;
182  * \endcode
183  *
184  * In C++03, the macro can only be used in the global namespace and
185  * is defined as:
186  *
187  * \code
188  * #define BOOST_TYPE_ERASURE_FREE(qualified_name, function_name, N)
189  * \endcode
190  *
191  * Example:
192  *
193  * \code
194  * BOOST_TYPE_ERASURE_FREE((boost)(has_to_string), to_string, 1)
195  * \endcode
196  *
197  * For backwards compatibility, this form is always accepted.
198  */
199 #define BOOST_TYPE_ERASURE_FREE(concept_name, function_name)
200 
201 #else
202 
203 #define BOOST_TYPE_ERASURE_FREE(qualified_name, function_name, N)                           \
204     BOOST_TYPE_ERASURE_FREE_I(                                                              \
205         qualified_name,                                                                     \
206         BOOST_PP_SEQ_ELEM(BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(qualified_name)), qualified_name), \
207         function_name,                                                                      \
208         N)
209 
210 #endif
211 
212 #else
213 
214 namespace boost {
215 namespace type_erasure {
216 
217 template<int... N>
218 struct index_list {};
219 
220 namespace detail {
221 
222 template<class... T>
223 struct first_placeholder;
224 
225 template<class T0, class... T>
226 struct first_placeholder<T0, T...> {
227     typedef typename ::boost::mpl::eval_if<is_placeholder<T0>,
228         ::boost::mpl::identity<T0>,
229         first_placeholder<T...>
230     >::type type;
231 };
232 
233 template<>
234 struct first_placeholder<> {};
235 
236 template<class... T>
237 struct first_placeholder_index;
238 
239 template<class T0, class... T>
240 struct first_placeholder_index<T0, T...> :
241     ::boost::mpl::eval_if<is_placeholder<T0>,
242         ::boost::mpl::int_<0>,
243         ::boost::mpl::next<first_placeholder_index<T...> >
244     >::type
245 {};
246 
247 template<class Sig>
248 struct transform_free_signature;
249 
250 template<class T, int N>
251 struct push_back_index;
252 
253 template<int... N, int X>
254 struct push_back_index<index_list<N...>, X>
255 {
256     typedef index_list<N..., X> type;
257 };
258 
259 template<int N>
260 struct make_index_list {
261     typedef typename push_back_index<
262         typename make_index_list<N-1>::type,
263         N-1
264     >::type type;
265 };
266 
267 template<>
268 struct make_index_list<0> {
269     typedef index_list<> type;
270 };
271 
272 #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) && \
273     !defined(BOOST_NO_CXX11_DECLTYPE)
274 
275 template<int N>
276 using make_index_list_t = typename ::boost::type_erasure::detail::make_index_list<N>::type;
277 
278 #if BOOST_WORKAROUND(BOOST_MSVC, == 1900)
279 
280 template<class... T>
281 struct first_placeholder_index_ :
282     ::boost::type_erasure::detail::first_placeholder_index<
283         ::boost::remove_cv_t< ::boost::remove_reference_t<T> >...
284     >
285 {};
286 template<class... T>
287 using first_placeholder_index_t =
288     typename ::boost::type_erasure::detail::first_placeholder_index_<T...>::type;
289 
290 #else
291 
292 template<class... T>
293 using first_placeholder_index_t =
294     typename ::boost::type_erasure::detail::first_placeholder_index<
295         ::boost::remove_cv_t< ::boost::remove_reference_t<T> >...
296     >::type;
297 
298 #endif
299 
300 template<class Base, class Tn, int I, class... T>
301 using free_param_t =
302     typename ::boost::mpl::eval_if_c<(::boost::type_erasure::detail::first_placeholder_index_t<T...>::value == I),
303             ::boost::type_erasure::detail::maybe_const_this_param<Tn, Base>, \
304             ::boost::type_erasure::as_param<Base, Tn>
305     >::type;
306 
307 template<class Sig, class ID>
308 struct free_interface_chooser
309 {
310     template<class Base, template<class> class C, template<class...> class F>
311     using apply = Base;
312 };
313 
314 template<class R, class... A>
315 struct free_interface_chooser<
316     R(A...),
317     typename ::boost::type_erasure::detail::first_placeholder<
318         ::boost::remove_cv_t< ::boost::remove_reference_t<A> >...>::type>
319 {
320     template<class Base, template<class> class C, template<class...> class F>
321     using apply = F<R(A...), Base,
322         ::boost::type_erasure::detail::make_index_list_t<sizeof...(A)> >;
323 };
324 
325 template<class Sig, template<class> class C, template<class...> class F>
326 struct free_choose_interface {
327     template<class Concept, class Base, class ID>
328     using apply = typename free_interface_chooser<Sig, ID>::template apply<Base, C, F>;
329 };
330 
331 /** INTERNAL ONLY */
332 #define BOOST_TYPE_ERASURE_FREE_I(concept_name, function_name)              \
333 template<class Sig>                                                         \
334 struct concept_name;                                                        \
335                                                                             \
336 namespace boost_type_erasure_impl {                                         \
337                                                                             \
338 template<class Sig, class Base, class Idx>                                  \
339 struct concept_name ## _free_interface;                                     \
340 template<class R, class... T, class Base, int... I>                         \
341 struct concept_name ## _free_interface<R(T...), Base, ::boost::type_erasure::index_list<I...> > : Base {\
342     friend ::boost::type_erasure::rebind_any_t<Base, R>                     \
343     function_name(                                                          \
344         ::boost::type_erasure::detail::free_param_t<Base, T, I, T...>... t) \
345     {                                                                       \
346         return ::boost::type_erasure::call(                                 \
347             concept_name<R(T...)>(),                                        \
348             std::forward< ::boost::type_erasure::detail::free_param_t<Base, T, I, T...> >(t)...);\
349     }                                                                       \
350 };                                                                          \
351                                                                             \
352 template<class Sig>                                                         \
353 struct concept_name ## free;                                                \
354                                                                             \
355 template<class R, class... T>                                               \
356 struct concept_name ## free<R(T...)> {                                      \
357     static R apply(T... t)                                                  \
358     { return function_name(std::forward<T>(t)...); }                        \
359 };                                                                          \
360                                                                             \
361 template<class... T>                                                        \
362 struct concept_name ## free<void(T...)> {                                   \
363     static void apply(T... t)                                               \
364     { function_name(std::forward<T>(t)...); }                               \
365 };                                                                          \
366                                                                             \
367 }                                                                           \
368                                                                             \
369 template<class Sig>                                                         \
370 struct concept_name :                                                       \
371     boost_type_erasure_impl::concept_name##free<Sig>                        \
372 {};                                                                         \
373                                                                             \
374 template<class Sig>                                                         \
375 ::boost::type_erasure::detail::free_choose_interface<Sig, concept_name,     \
376     boost_type_erasure_impl::concept_name ## _free_interface>               \
377 boost_type_erasure_find_interface(concept_name<Sig>);
378 
379 #define BOOST_TYPE_ERASURE_FREE_SIMPLE(name, ...) \
380     BOOST_TYPE_ERASURE_FREE_I(has_ ## name, name)
381 
382 #define BOOST_TYPE_ERASURE_FREE_NS_I(concept_name, name)  \
383     BOOST_TYPE_ERASURE_FREE_I(concept_name, name)
384 
385 #define BOOST_TYPE_ERASURE_FREE_NS(concept_name, name)      \
386     BOOST_TYPE_ERASURE_OPEN_NAMESPACE(concept_name)         \
387     BOOST_TYPE_ERASURE_FREE_NS_I(BOOST_PP_SEQ_ELEM(BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(concept_name)), concept_name), name) \
388     BOOST_TYPE_ERASURE_CLOSE_NAMESPACE(concept_name)
389 
390 #define BOOST_TYPE_ERASURE_FREE_NAMED(concept_name, name, ...)  \
391     BOOST_PP_IF(BOOST_PP_IS_BEGIN_PARENS(concept_name),         \
392         BOOST_TYPE_ERASURE_FREE_NS,                             \
393         BOOST_TYPE_ERASURE_FREE_I)                              \
394     (concept_name, name)
395 
396 #define BOOST_TYPE_ERASURE_FREE_CAT(x, y) x y
397 
398 #define BOOST_TYPE_ERASURE_FREE(name, ...)              \
399     BOOST_TYPE_ERASURE_FREE_CAT(                        \
400         BOOST_PP_IF(BOOST_VMD_IS_EMPTY(__VA_ARGS__),    \
401             BOOST_TYPE_ERASURE_FREE_SIMPLE,             \
402             BOOST_TYPE_ERASURE_FREE_NAMED),             \
403         (name, __VA_ARGS__))
404 
405 #else
406 
407 /** INTERNAL ONLY */
408 #define BOOST_TYPE_ERASURE_FREE_II(qual_name, concept_name, function_name)  \
409     BOOST_TYPE_ERASURE_OPEN_NAMESPACE(qual_name)                        \
410                                                                         \
411     template<class Sig>                                                 \
412     struct concept_name;                                                \
413                                                                         \
414     template<class R, class... T>                                       \
415     struct concept_name<R(T...)> {                                      \
416         static R apply(T... t)                                          \
417         { return function_name(std::forward<T>(t)...); }                \
418     };                                                                  \
419                                                                         \
420     template<class... T>                                                \
421     struct concept_name<void(T...)> {                                   \
422         static void apply(T... t)                                       \
423         { function_name(std::forward<T>(t)...); }                       \
424     };                                                                  \
425                                                                         \
426     BOOST_TYPE_ERASURE_CLOSE_NAMESPACE(qual_name)                       \
427                                                                         \
428     namespace boost {                                                   \
429     namespace type_erasure {                                            \
430                                                                         \
431     template<class Sig, class Base, class Idx>                          \
432     struct inject ## concept_name;                                      \
433     template<class R, class... T, class Base, int... I>                 \
434     struct inject ## concept_name<R(T...), Base, index_list<I...> > : Base {\
435         typedef typename ::boost::type_erasure::detail::first_placeholder_index<    \
436             typename ::boost::remove_cv<                                \
437                 typename ::boost::remove_reference<T>::type             \
438             >::type...                                                  \
439         >::type _boost_type_erasure_free_p_idx;                         \
440         friend typename ::boost::type_erasure::rebind_any<Base, R>::type\
441         function_name(                                                  \
442             typename ::boost::mpl::eval_if_c<(_boost_type_erasure_free_p_idx::value == I), \
443                 ::boost::type_erasure::detail::maybe_const_this_param<T, Base>, \
444                 ::boost::type_erasure::as_param<Base, T>                \
445             >::type... t)                                               \
446        {                                                                \
447             return ::boost::type_erasure::call(                         \
448                 BOOST_TYPE_ERASURE_QUALIFIED_NAME(qual_name)<R(T...)>(),\
449                 std::forward<typename ::boost::mpl::eval_if_c<(_boost_type_erasure_free_p_idx::value == I), \
450                     ::boost::type_erasure::detail::maybe_const_this_param<T, Base>, \
451                     ::boost::type_erasure::as_param<Base, T>            \
452                 >::type>(t)...);                                        \
453         }                                                               \
454     };                                                                  \
455                                                                         \
456     template<class R, class... T, class Base>                           \
457     struct concept_interface<                                           \
458         BOOST_TYPE_ERASURE_QUALIFIED_NAME(qual_name)<R(T...)>,          \
459         Base,                                                           \
460         typename ::boost::type_erasure::detail::first_placeholder<      \
461             typename ::boost::remove_cv<typename ::boost::remove_reference<T>::type>::type...>::type  \
462     > :  inject ## concept_name<R(T...), Base, typename ::boost::type_erasure::detail::make_index_list<sizeof...(T)>::type>\
463     {};                                                                 \
464                                                                         \
465     }                                                                   \
466     }
467 
468 
469 /** INTERNAL ONLY */
470 #define BOOST_TYPE_ERASURE_FREE_I(namespace_name, concept_name, function_name)              \
471     BOOST_TYPE_ERASURE_FREE_II(namespace_name, concept_name, function_name)
472 
473 #define BOOST_TYPE_ERASURE_FREE(qualified_name, function_name, ...)                         \
474     BOOST_TYPE_ERASURE_FREE_I(                                                              \
475         qualified_name,                                                                     \
476         BOOST_PP_SEQ_ELEM(BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(qualified_name)), qualified_name), \
477         function_name)
478 
479 #endif
480 
481 }
482 }
483 }
484 
485 #endif
486 
487 #endif
488