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