dynamic_any_cast.hpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. // Boost.TypeErasure library
  2. //
  3. // Copyright 2015 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. #ifndef BOOST_TYPE_ERASURE_DYNAMIC_ANY_CAST_HPP_INCLUDED
  11. #define BOOST_TYPE_ERASURE_DYNAMIC_ANY_CAST_HPP_INCLUDED
  12. #include <boost/type_erasure/detail/normalize.hpp>
  13. #include <boost/type_erasure/binding_of.hpp>
  14. #include <boost/type_erasure/static_binding.hpp>
  15. #include <boost/type_erasure/dynamic_binding.hpp>
  16. #include <boost/type_erasure/concept_of.hpp>
  17. #include <boost/type_erasure/placeholder_of.hpp>
  18. #include <boost/type_erasure/any.hpp>
  19. #include <boost/type_erasure/binding.hpp>
  20. #include <boost/mpl/vector.hpp>
  21. #include <boost/mpl/set.hpp>
  22. #include <boost/mpl/fold.hpp>
  23. #include <boost/type_traits/add_const.hpp>
  24. #include <boost/type_traits/add_reference.hpp>
  25. #include <boost/type_traits/remove_const.hpp>
  26. #include <boost/type_traits/remove_reference.hpp>
  27. namespace boost {
  28. namespace type_erasure {
  29. namespace detail {
  30. template<class P, class P2, class Any>
  31. struct make_ref_placeholder;
  32. template<class P, class P2, class Any>
  33. struct make_ref_placeholder<P, P2, const Any&> { typedef const P& type; };
  34. template<class P, class P2, class Any>
  35. struct make_ref_placeholder<P, P2, Any&> { typedef P& type; };
  36. template<class P, class P2, class Any>
  37. struct make_ref_placeholder<P, P2&, const Any&> { typedef P& type; };
  38. template<class P, class P2, class Any>
  39. struct make_ref_placeholder<P, P2&, Any&> { typedef P& type; };
  40. template<class P, class P2, class Any>
  41. struct make_ref_placeholder<P, const P2&, const Any&> { typedef const P& type; };
  42. template<class P, class P2, class Any>
  43. struct make_ref_placeholder<P, const P2&, Any&> { typedef const P& type; };
  44. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  45. template<class P, class P2, class Any>
  46. struct make_ref_placeholder { typedef P&& type; };
  47. template<class P, class P2, class Any>
  48. struct make_ref_placeholder<P, P2&, Any> { typedef P& type; };
  49. template<class P, class P2, class Any>
  50. struct make_ref_placeholder<P, const P2&, Any> { typedef const P& type; };
  51. template<class P, class P2, class Any>
  52. struct make_ref_placeholder<P, P2&&, Any> { typedef P&& type; };
  53. template<class P, class P2, class Any>
  54. struct make_ref_placeholder<P, P2&&, const Any&> { typedef const P& type; };
  55. template<class P, class P2, class Any>
  56. struct make_ref_placeholder<P, P2&&, Any&> { typedef P& type; };
  57. #endif
  58. template<class R, class Tag>
  59. struct make_result_placeholder_map
  60. {
  61. typedef ::boost::mpl::map<
  62. ::boost::mpl::pair<
  63. typename ::boost::remove_const<
  64. typename ::boost::remove_reference<
  65. typename ::boost::type_erasure::placeholder_of<R>::type
  66. >::type
  67. >::type,
  68. typename ::boost::remove_const<
  69. typename ::boost::remove_reference<
  70. Tag
  71. >::type
  72. >::type
  73. >
  74. > type;
  75. };
  76. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  77. template<class R, class Any, class Map>
  78. R dynamic_any_cast_impl(Any&& arg, const static_binding<Map>& map)
  79. #else
  80. template<class R, class Any, class Map>
  81. R dynamic_any_cast_impl(Any& arg, const static_binding<Map>& map)
  82. #endif
  83. {
  84. typedef typename ::boost::remove_const<typename ::boost::remove_reference<Any>::type>::type src_type;
  85. typedef typename ::boost::type_erasure::detail::normalize_concept<
  86. typename ::boost::type_erasure::concept_of<src_type>::type
  87. >::type normalized;
  88. typedef typename ::boost::mpl::fold<
  89. normalized,
  90. #ifndef BOOST_TYPE_ERASURE_USE_MP11
  91. ::boost::mpl::set0<>,
  92. #else
  93. ::boost::mp11::mp_list<>,
  94. #endif
  95. ::boost::type_erasure::detail::get_placeholders<
  96. ::boost::mpl::_2,
  97. ::boost::mpl::_1
  98. >
  99. >::type placeholders;
  100. #ifndef BOOST_TYPE_ERASURE_USE_MP11
  101. typedef ::boost::type_erasure::detail::substitution_map< ::boost::mpl::map0<> > identity_map;
  102. #else
  103. typedef ::boost::type_erasure::detail::make_identity_placeholder_map<normalized> identity_map;
  104. #endif
  105. ::boost::type_erasure::dynamic_binding<placeholders> my_binding(
  106. ::boost::type_erasure::binding_of(arg),
  107. ::boost::type_erasure::make_binding<identity_map>());
  108. typedef typename ::boost::remove_const<
  109. typename ::boost::remove_reference<
  110. typename ::boost::type_erasure::placeholder_of<R>::type
  111. >::type
  112. >::type result_placeholder;
  113. ::boost::type_erasure::binding< typename ::boost::type_erasure::concept_of<R>::type> new_binding(
  114. my_binding,
  115. map);
  116. typedef ::boost::type_erasure::any<
  117. typename ::boost::type_erasure::concept_of<R>::type,
  118. typename ::boost::type_erasure::detail::make_ref_placeholder<
  119. result_placeholder,
  120. typename ::boost::type_erasure::placeholder_of<src_type>::type,
  121. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  122. Any
  123. #else
  124. Any&
  125. #endif
  126. >::type
  127. > result_ref_type;
  128. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  129. return result_ref_type(std::forward<Any>(arg), new_binding);
  130. #else
  131. return result_ref_type(arg, new_binding);
  132. #endif
  133. }
  134. }
  135. #ifdef BOOST_TYPE_ERASURE_DOXYGEN
  136. /**
  137. * Downcasts or crosscasts an @ref any.
  138. *
  139. * \pre @c R and @c Any must both be specializations of @ref any.
  140. * \pre PlaceholderMap must be an MPL map with a key
  141. * for every non-deduced placeholder used by R.
  142. * The value associated with each key should
  143. * be the corresponding placeholder in Any.
  144. * \pre The concept of Any must include @ref typeid_, for every
  145. * @ref placeholder which is used by R.
  146. *
  147. * The single argument form can only be used when @c R uses
  148. * a single non-deduced placeholder.
  149. *
  150. * \throws bad_any_cast if the concepts used by R were
  151. * not previously registered via a call to
  152. * \register_binding.
  153. *
  154. * Example:
  155. * \code
  156. * // Assume that typeid_<>, copy_constructible<>, and incrementable<>
  157. * // have all been registered for int.
  158. * any<mpl::vector<typeid_<>, copy_constructible<> > > x(1);
  159. * typedef any<
  160. * mpl::vector<
  161. * typeid_<>,
  162. * copy_constructible<>,
  163. * incrementable<>
  164. * >
  165. * > incrementable_any;
  166. * auto y = dynamic_any_cast<incrementable_any>(x);
  167. * ++y;
  168. * assert(any_cast<int>(y) == 2);
  169. * \endcode
  170. */
  171. template<class R, class Any>
  172. R dynamic_any_cast(Any&& arg);
  173. /**
  174. * \overload
  175. */
  176. template<class R, class Any, class Map>
  177. R dynamic_any_cast(Any&& arg, const static_binding<Map>&);
  178. #else
  179. template<class R, class Concept, class Tag>
  180. R dynamic_any_cast(const any<Concept, Tag>& arg)
  181. {
  182. return ::boost::type_erasure::detail::dynamic_any_cast_impl<R>(arg,
  183. ::boost::type_erasure::make_binding<typename ::boost::type_erasure::detail::make_result_placeholder_map<R, Tag>::type>());
  184. }
  185. template<class R, class Concept, class Tag>
  186. R dynamic_any_cast(any<Concept, Tag>& arg)
  187. {
  188. return ::boost::type_erasure::detail::dynamic_any_cast_impl<R>(arg,
  189. ::boost::type_erasure::make_binding<typename ::boost::type_erasure::detail::make_result_placeholder_map<R, Tag>::type>());
  190. }
  191. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  192. template<class R, class Concept, class Tag>
  193. R dynamic_any_cast(any<Concept, Tag>&& arg)
  194. {
  195. return ::boost::type_erasure::detail::dynamic_any_cast_impl<R>(::std::move(arg),
  196. ::boost::type_erasure::make_binding<typename ::boost::type_erasure::detail::make_result_placeholder_map<R, Tag>::type>());
  197. }
  198. #endif
  199. template<class R, class Concept, class Tag, class Map>
  200. R dynamic_any_cast(const any<Concept, Tag>& arg, const static_binding<Map>& map)
  201. {
  202. return ::boost::type_erasure::detail::dynamic_any_cast_impl<R>(arg, map);
  203. }
  204. template<class R, class Concept, class Tag, class Map>
  205. R dynamic_any_cast(any<Concept, Tag>& arg, const static_binding<Map>& map)
  206. {
  207. return ::boost::type_erasure::detail::dynamic_any_cast_impl<R>(arg, map);
  208. }
  209. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  210. template<class R, class Concept, class Tag, class Map>
  211. R dynamic_any_cast(any<Concept, Tag>&& arg, const static_binding<Map>& map)
  212. {
  213. return ::boost::type_erasure::detail::dynamic_any_cast_impl<R>(::std::move(arg), map);
  214. }
  215. #endif
  216. #endif
  217. }
  218. }
  219. #endif