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/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> 37 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) 42 43 namespace boost { 44 namespace type_erasure { 45 namespace detail { 46 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)> 52 >::type type; 53 }; 54 55 template<> 56 struct first_placeholder<> {}; 57 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)> > 63 >::type 64 {}; 65 66 } 67 } 68 } 69 70 /** INTERNAL ONLY */ 71 #define BOOST_TYPE_ERASURE_FREE_QUALIFIED_ID(seq, N) \ 72 BOOST_TYPE_ERASURE_QUALIFIED_NAME(seq)<R(BOOST_PP_ENUM_PARAMS(N, T))> 73 74 /** INTERNAL ONLY */ 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 77 78 /** INTERNAL ONLY */ 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) 84 85 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES 86 87 /** INTERNAL ONLY */ 88 #define BOOST_TYPE_ERASURE_FREE_FORWARD_I(z, n, data) ::std::forward<BOOST_PP_CAT(T, n)>(BOOST_PP_CAT(t, n)) 89 /** INTERNAL ONLY */ 90 #define BOOST_TYPE_ERASURE_FREE_FORWARD(n) BOOST_PP_ENUM(n, BOOST_TYPE_ERASURE_FREE_FORWARD_I, ~) 91 /** INTERNAL ONLY */ 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)) 97 98 #else 99 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) 102 103 #endif 104 105 /** INTERNAL ONLY */ 106 #define BOOST_TYPE_ERASURE_FREE_II(qual_name, concept_name, function_name, N) \ 107 BOOST_TYPE_ERASURE_OPEN_NAMESPACE(qual_name) \ 108 \ 109 template<class Sig> \ 110 struct concept_name; \ 111 \ 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)); } \ 116 }; \ 117 \ 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)); } \ 122 }; \ 123 \ 124 BOOST_TYPE_ERASURE_CLOSE_NAMESPACE(qual_name) \ 125 \ 126 namespace boost { \ 127 namespace type_erasure { \ 128 \ 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), \ 132 Base, \ 133 typename ::boost::type_erasure::detail::first_placeholder< \ 134 BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_FREE_UNQUALIFIED_PARAM_TYPE, ~)>::type \ 135 > : Base { \ 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, ~)) \ 141 { \ 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, ~)); \ 145 } \ 146 }; \ 147 \ 148 } \ 149 } 150 151 #else 152 153 namespace boost { 154 namespace type_erasure { 155 156 template<int... N> 157 struct index_list {}; 158 159 namespace detail { 160 161 template<class... T> 162 struct first_placeholder; 163 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...> 169 >::type type; 170 }; 171 172 template<> 173 struct first_placeholder<> {}; 174 175 template<class... T> 176 struct first_placeholder_index; 177 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...> > 183 >::type 184 {}; 185 186 template<class Sig> 187 struct transform_free_signature; 188 189 template<class T, int N> 190 struct push_back_index; 191 192 template<int... N, int X> 193 struct push_back_index<index_list<N...>, X> 194 { 195 typedef index_list<N..., X> type; 196 }; 197 198 template<int N> 199 struct make_index_list { 200 typedef typename push_back_index< 201 typename make_index_list<N-1>::type, 202 N-1 203 >::type type; 204 }; 205 206 template<> 207 struct make_index_list<0> { 208 typedef index_list<> type; 209 }; 210 211 } 212 } 213 } 214 215 /** INTERNAL ONLY */ 216 #define BOOST_TYPE_ERASURE_FREE_II(qual_name, concept_name, function_name, N) \ 217 BOOST_TYPE_ERASURE_OPEN_NAMESPACE(qual_name) \ 218 \ 219 template<class Sig> \ 220 struct concept_name; \ 221 \ 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)...); } \ 226 }; \ 227 \ 228 template<class... T> \ 229 struct concept_name<void(T...)> { \ 230 static void apply(T... t) \ 231 { function_name(std::forward<T>(t)...); } \ 232 }; \ 233 \ 234 BOOST_TYPE_ERASURE_CLOSE_NAMESPACE(qual_name) \ 235 \ 236 namespace boost { \ 237 namespace type_erasure { \ 238 \ 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 \ 246 >::type... \ 247 >::type _boost_type_erasure_free_p_idx; \ 248 friend typename ::boost::type_erasure::rebind_any<Base, R>::type\ 249 function_name( \ 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> \ 253 >::type... t) \ 254 { \ 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> \ 260 >::type>(t)...); \ 261 } \ 262 }; \ 263 \ 264 template<class R, class... T, class Base> \ 265 struct concept_interface< \ 266 BOOST_TYPE_ERASURE_QUALIFIED_NAME(qual_name)<R(T...)>, \ 267 Base, \ 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>\ 271 {}; \ 272 \ 273 } \ 274 } 275 276 #endif 277 278 /** INTERNAL ONLY */ 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) 281 282 /** 283 * \brief Defines a primitive concept for a free function. 284 * 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. 289 * 290 * The declaration of the concept is 291 * \code 292 * template<class Sig> 293 * struct ::namespace1::namespace2::...::concept_name; 294 * \endcode 295 * where Sig is a function type giving the 296 * signature of the function. 297 * 298 * This macro can only be used in the global namespace. 299 * 300 * Example: 301 * 302 * \code 303 * BOOST_TYPE_ERASURE_FREE((boost)(has_to_string), to_string, 1) 304 * \endcode 305 */ 306 #define BOOST_TYPE_ERASURE_FREE(qualified_name, function_name, N) \ 307 BOOST_TYPE_ERASURE_FREE_I( \ 308 qualified_name, \ 309 BOOST_PP_SEQ_ELEM(BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(qualified_name)), qualified_name), \ 310 function_name, \ 311 N) 312 313 #endif 314