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> |
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 | |