1 // Boost.TypeErasure library
3 // Copyright 2012 Steven Watanabe
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)
11 #ifndef BOOST_TYPE_ERASURE_FREE_HPP_INCLUDED
12 #define BOOST_TYPE_ERASURE_FREE_HPP_INCLUDED
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/type_traits/remove_reference.hpp>
23 #include <boost/type_traits/remove_cv.hpp>
24 #include <boost/mpl/eval_if.hpp>
25 #include <boost/mpl/identity.hpp>
26 #include <boost/mpl/int.hpp>
27 #include <boost/mpl/next.hpp>
28 #include <boost/type_erasure/detail/macro.hpp>
29 #include <boost/type_erasure/detail/const.hpp>
30 #include <boost/type_erasure/config.hpp>
31 #include <boost/type_erasure/derived.hpp>
32 #include <boost/type_erasure/rebind_any.hpp>
33 #include <boost/type_erasure/param.hpp>
34 #include <boost/type_erasure/is_placeholder.hpp>
35 #include <boost/type_erasure/call.hpp>
36 #include <boost/type_erasure/concept_interface.hpp>
38 #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || \
39 defined(BOOST_NO_CXX11_RVALUE_REFERENCES) || \
40 defined(BOOST_TYPE_ERASURE_DOXYGEN) || \
41 BOOST_WORKAROUND(BOOST_MSVC, == 1800)
44 namespace type_erasure {
47 template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(BOOST_TYPE_ERASURE_MAX_ARITY, class T, void)>
48 struct first_placeholder {
49 typedef typename ::boost::mpl::eval_if<is_placeholder<T0>,
50 ::boost::mpl::identity<T0>,
51 first_placeholder<BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_TYPE_ERASURE_MAX_ARITY, T)>
56 struct first_placeholder<> {};
58 template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(BOOST_TYPE_ERASURE_MAX_ARITY, class T, void)>
59 struct first_placeholder_index :
60 ::boost::mpl::eval_if<is_placeholder<T0>,
61 ::boost::mpl::int_<0>,
62 ::boost::mpl::next<first_placeholder_index<BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_TYPE_ERASURE_MAX_ARITY, T)> >
71 #define BOOST_TYPE_ERASURE_FREE_QUALIFIED_ID(seq, N) \
72 BOOST_TYPE_ERASURE_QUALIFIED_NAME(seq)<R(BOOST_PP_ENUM_PARAMS(N, T))>
75 #define BOOST_TYPE_ERASURE_FREE_UNQUALIFIED_PARAM_TYPE(z, n, data) \
76 typename ::boost::remove_cv<typename ::boost::remove_reference<BOOST_PP_CAT(T, n)>::type>::type
79 #define BOOST_TYPE_ERASURE_FREE_PARAM_TYPE(z, n, data) \
80 typename ::boost::mpl::eval_if_c<(_boost_type_erasure_free_p_idx::value == n), \
81 ::boost::type_erasure::detail::maybe_const_this_param<BOOST_PP_CAT(T, n), Base>, \
82 ::boost::type_erasure::as_param<Base, BOOST_PP_CAT(T, n)> \
83 >::type BOOST_PP_CAT(t, n)
85 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
88 #define BOOST_TYPE_ERASURE_FREE_FORWARD_I(z, n, data) ::std::forward<BOOST_PP_CAT(T, n)>(BOOST_PP_CAT(t, n))
90 #define BOOST_TYPE_ERASURE_FREE_FORWARD(n) BOOST_PP_ENUM(n, BOOST_TYPE_ERASURE_FREE_FORWARD_I, ~)
92 #define BOOST_TYPE_ERASURE_FREE_FORWARD_PARAM_I(z, n, data) \
93 ::std::forward<typename ::boost::mpl::eval_if_c<(_boost_type_erasure_free_p_idx::value == n), \
94 ::boost::type_erasure::detail::maybe_const_this_param<BOOST_PP_CAT(T, n), Base>, \
95 ::boost::type_erasure::as_param<Base, BOOST_PP_CAT(T, n)> \
96 >::type>(BOOST_PP_CAT(t, n))
100 #define BOOST_TYPE_ERASURE_FREE_FORWARD(n) BOOST_PP_ENUM_PARAMS(n, t)
101 #define BOOST_TYPE_ERASURE_FREE_FORWARD_PARAM_I(z, n, data) BOOST_PP_CAT(t, n)
106 #define BOOST_TYPE_ERASURE_FREE_II(qual_name, concept_name, function_name, N) \
107 BOOST_TYPE_ERASURE_OPEN_NAMESPACE(qual_name) \
109 template<class Sig> \
110 struct concept_name; \
112 template<class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T)> \
113 struct concept_name<R(BOOST_PP_ENUM_PARAMS(N, T))> { \
114 static R apply(BOOST_PP_ENUM_BINARY_PARAMS(N, T, t)) \
115 { return function_name(BOOST_TYPE_ERASURE_FREE_FORWARD(N)); } \
118 template<BOOST_PP_ENUM_PARAMS(N, class T)> \
119 struct concept_name<void(BOOST_PP_ENUM_PARAMS(N, T))> { \
120 static void apply(BOOST_PP_ENUM_BINARY_PARAMS(N, T, t)) \
121 { function_name(BOOST_TYPE_ERASURE_FREE_FORWARD(N)); } \
124 BOOST_TYPE_ERASURE_CLOSE_NAMESPACE(qual_name) \
127 namespace type_erasure { \
129 template<class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T), class Base> \
130 struct concept_interface< \
131 BOOST_TYPE_ERASURE_FREE_QUALIFIED_ID(qual_name, N), \
133 typename ::boost::type_erasure::detail::first_placeholder< \
134 BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_FREE_UNQUALIFIED_PARAM_TYPE, ~)>::type \
136 typedef typename ::boost::type_erasure::detail::first_placeholder_index< \
137 BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_FREE_UNQUALIFIED_PARAM_TYPE, ~)>::type \
138 _boost_type_erasure_free_p_idx; \
139 friend typename ::boost::type_erasure::rebind_any<Base, R>::type function_name( \
140 BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_FREE_PARAM_TYPE, ~)) \
142 return ::boost::type_erasure::call( \
143 BOOST_TYPE_ERASURE_FREE_QUALIFIED_ID(qual_name, N)() \
144 BOOST_PP_ENUM_TRAILING(N, BOOST_TYPE_ERASURE_FREE_FORWARD_PARAM_I, ~)); \
154 namespace type_erasure {
157 struct index_list {};
162 struct first_placeholder;
164 template<class T0, class... T>
165 struct first_placeholder<T0, T...> {
166 typedef typename ::boost::mpl::eval_if<is_placeholder<T0>,
167 ::boost::mpl::identity<T0>,
168 first_placeholder<T...>
173 struct first_placeholder<> {};
176 struct first_placeholder_index;
178 template<class T0, class... T>
179 struct first_placeholder_index<T0, T...> :
180 ::boost::mpl::eval_if<is_placeholder<T0>,
181 ::boost::mpl::int_<0>,
182 ::boost::mpl::next<first_placeholder_index<T...> >
187 struct transform_free_signature;
189 template<class T, int N>
190 struct push_back_index;
192 template<int... N, int X>
193 struct push_back_index<index_list<N...>, X>
195 typedef index_list<N..., X> type;
199 struct make_index_list {
200 typedef typename push_back_index<
201 typename make_index_list<N-1>::type,
207 struct make_index_list<0> {
208 typedef index_list<> type;
216 #define BOOST_TYPE_ERASURE_FREE_II(qual_name, concept_name, function_name, N) \
217 BOOST_TYPE_ERASURE_OPEN_NAMESPACE(qual_name) \
219 template<class Sig> \
220 struct concept_name; \
222 template<class R, class... T> \
223 struct concept_name<R(T...)> { \
224 static R apply(T... t) \
225 { return function_name(std::forward<T>(t)...); } \
228 template<class... T> \
229 struct concept_name<void(T...)> { \
230 static void apply(T... t) \
231 { function_name(std::forward<T>(t)...); } \
234 BOOST_TYPE_ERASURE_CLOSE_NAMESPACE(qual_name) \
237 namespace type_erasure { \
239 template<class Sig, class Base, class Idx> \
240 struct inject ## concept_name; \
241 template<class R, class... T, class Base, int... I> \
242 struct inject ## concept_name<R(T...), Base, index_list<I...> > : Base {\
243 typedef typename ::boost::type_erasure::detail::first_placeholder_index< \
244 typename ::boost::remove_cv< \
245 typename ::boost::remove_reference<T>::type \
247 >::type _boost_type_erasure_free_p_idx; \
248 friend typename ::boost::type_erasure::rebind_any<Base, R>::type\
250 typename ::boost::mpl::eval_if_c<(_boost_type_erasure_free_p_idx::value == I), \
251 ::boost::type_erasure::detail::maybe_const_this_param<T, Base>, \
252 ::boost::type_erasure::as_param<Base, T> \
255 return ::boost::type_erasure::call( \
256 BOOST_TYPE_ERASURE_QUALIFIED_NAME(qual_name)<R(T...)>(),\
257 std::forward<typename ::boost::mpl::eval_if_c<(_boost_type_erasure_free_p_idx::value == I), \
258 ::boost::type_erasure::detail::maybe_const_this_param<T, Base>, \
259 ::boost::type_erasure::as_param<Base, T> \
264 template<class R, class... T, class Base> \
265 struct concept_interface< \
266 BOOST_TYPE_ERASURE_QUALIFIED_NAME(qual_name)<R(T...)>, \
268 typename ::boost::type_erasure::detail::first_placeholder< \
269 typename ::boost::remove_cv<typename ::boost::remove_reference<T>::type>::type...>::type \
270 > : inject ## concept_name<R(T...), Base, typename ::boost::type_erasure::detail::make_index_list<sizeof...(T)>::type>\
279 #define BOOST_TYPE_ERASURE_FREE_I(namespace_name, concept_name, function_name, N)\
280 BOOST_TYPE_ERASURE_FREE_II(namespace_name, concept_name, function_name, N)
283 * \brief Defines a primitive concept for a free function.
285 * \param qualified_name should be a preprocessor sequence
286 * of the form (namespace1)(namespace2)...(concept_name).
287 * \param function_name is the name of the function.
288 * \param N is the number of arguments of the function.
290 * The declaration of the concept is
292 * template<class Sig>
293 * struct ::namespace1::namespace2::...::concept_name;
295 * where Sig is a function type giving the
296 * signature of the function.
298 * This macro can only be used in the global namespace.
303 * BOOST_TYPE_ERASURE_FREE((boost)(has_to_string), to_string, 1)
306 #define BOOST_TYPE_ERASURE_FREE(qualified_name, function_name, N) \
307 BOOST_TYPE_ERASURE_FREE_I( \
309 BOOST_PP_SEQ_ELEM(BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(qualified_name)), qualified_name), \