polymorphic_get.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. //-----------------------------------------------------------------------------
  2. // boost variant/polymorphic_get.hpp header file
  3. // See http://www.boost.org for updates, documentation, and revision history.
  4. //-----------------------------------------------------------------------------
  5. //
  6. // Copyright (c) 2013-2015 Antony Polukhin
  7. //
  8. // Distributed under the Boost Software License, Version 1.0. (See
  9. // accompanying file LICENSE_1_0.txt or copy at
  10. // http://www.boost.org/LICENSE_1_0.txt)
  11. #ifndef BOOST_VARIANT_POLYMORPHIC_GET_HPP
  12. #define BOOST_VARIANT_POLYMORPHIC_GET_HPP
  13. #include <exception>
  14. #include "boost/config.hpp"
  15. #include "boost/detail/workaround.hpp"
  16. #include "boost/static_assert.hpp"
  17. #include "boost/throw_exception.hpp"
  18. #include "boost/utility/addressof.hpp"
  19. #include "boost/variant/variant_fwd.hpp"
  20. #include "boost/variant/get.hpp"
  21. #include "boost/type_traits/add_reference.hpp"
  22. #include "boost/type_traits/add_pointer.hpp"
  23. #include "boost/type_traits/is_base_of.hpp"
  24. namespace boost {
  25. //////////////////////////////////////////////////////////////////////////
  26. // class bad_polymorphic_get
  27. //
  28. // The exception thrown in the event of a failed get of a value.
  29. //
  30. class BOOST_SYMBOL_VISIBLE bad_polymorphic_get
  31. : public bad_get
  32. {
  33. public: // std::exception implementation
  34. virtual const char * what() const BOOST_NOEXCEPT_OR_NOTHROW
  35. {
  36. return "boost::bad_polymorphic_get: "
  37. "failed value get using boost::polymorphic_get";
  38. }
  39. };
  40. //////////////////////////////////////////////////////////////////////////
  41. // function template get<T>
  42. //
  43. // Retrieves content of given variant object if content is of type T.
  44. // Otherwise: pointer ver. returns 0; reference ver. throws bad_get.
  45. //
  46. namespace detail { namespace variant {
  47. ///////////////////////////////////////////////////////////////////////////////////////////////////
  48. // polymorphic metafunctions to detect index of a value
  49. //
  50. template <class Types, class T>
  51. struct element_polymorphic_iterator_impl :
  52. boost::mpl::find_if<
  53. Types,
  54. boost::mpl::or_<
  55. variant_element_functor<boost::mpl::_1, T>,
  56. variant_element_functor<boost::mpl::_1, typename boost::remove_cv<T>::type >,
  57. boost::is_base_of<T, boost::mpl::_1>
  58. >
  59. >
  60. {};
  61. template <class Variant, class T>
  62. struct holds_element_polymorphic :
  63. boost::mpl::not_<
  64. boost::is_same<
  65. typename boost::mpl::end<typename Variant::types>::type,
  66. typename element_polymorphic_iterator_impl<typename Variant::types, typename boost::remove_reference<T>::type >::type
  67. >
  68. >
  69. {};
  70. // (detail) class template get_polymorphic_visitor
  71. //
  72. // Generic static visitor that: if the value is of the specified
  73. // type or of a type derived from specified, returns a pointer
  74. // to the value it visits; else a null pointer.
  75. //
  76. template <typename Base>
  77. struct get_polymorphic_visitor
  78. {
  79. private: // private typedefs
  80. typedef get_polymorphic_visitor<Base> this_type;
  81. typedef typename add_pointer<Base>::type pointer;
  82. typedef typename add_reference<Base>::type reference;
  83. pointer get(reference operand, boost::true_type) const BOOST_NOEXCEPT
  84. {
  85. return boost::addressof(operand);
  86. }
  87. template <class T>
  88. pointer get(T&, boost::false_type) const BOOST_NOEXCEPT
  89. {
  90. return static_cast<pointer>(0);
  91. }
  92. public: // visitor interfaces
  93. typedef pointer result_type;
  94. template <typename U>
  95. pointer operator()(U& operand) const BOOST_NOEXCEPT
  96. {
  97. typedef boost::integral_constant<
  98. bool,
  99. boost::mpl::or_<
  100. boost::is_base_of<Base, U>,
  101. boost::is_same<Base, U>,
  102. boost::is_same<typename boost::remove_cv<Base>::type, U >
  103. >::value
  104. > tag_t;
  105. return this_type::get(operand, tag_t());
  106. }
  107. };
  108. }} // namespace detail::variant
  109. #ifndef BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE
  110. # if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0551))
  111. # define BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(t)
  112. # else
  113. # define BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(t) \
  114. , t* = 0
  115. # endif
  116. #endif
  117. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  118. // polymorphic_relaxed_get
  119. //
  120. template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
  121. inline
  122. typename add_pointer<U>::type
  123. polymorphic_relaxed_get(
  124. boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
  125. BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
  126. ) BOOST_NOEXCEPT
  127. {
  128. typedef typename add_pointer<U>::type U_ptr;
  129. if (!operand) return static_cast<U_ptr>(0);
  130. detail::variant::get_polymorphic_visitor<U> v;
  131. return operand->apply_visitor(v);
  132. }
  133. template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
  134. inline
  135. typename add_pointer<const U>::type
  136. polymorphic_relaxed_get(
  137. const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
  138. BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
  139. ) BOOST_NOEXCEPT
  140. {
  141. typedef typename add_pointer<const U>::type U_ptr;
  142. if (!operand) return static_cast<U_ptr>(0);
  143. detail::variant::get_polymorphic_visitor<const U> v;
  144. return operand->apply_visitor(v);
  145. }
  146. template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
  147. inline
  148. typename add_reference<U>::type
  149. polymorphic_relaxed_get(
  150. boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
  151. BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
  152. )
  153. {
  154. typedef typename add_pointer<U>::type U_ptr;
  155. U_ptr result = polymorphic_relaxed_get<U>(&operand);
  156. if (!result)
  157. boost::throw_exception(bad_polymorphic_get());
  158. return *result;
  159. }
  160. template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
  161. inline
  162. typename add_reference<const U>::type
  163. polymorphic_relaxed_get(
  164. const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
  165. BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
  166. )
  167. {
  168. typedef typename add_pointer<const U>::type U_ptr;
  169. U_ptr result = polymorphic_relaxed_get<const U>(&operand);
  170. if (!result)
  171. boost::throw_exception(bad_polymorphic_get());
  172. return *result;
  173. }
  174. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  175. // polymorphic_strict_get
  176. //
  177. template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
  178. inline
  179. typename add_pointer<U>::type
  180. polymorphic_strict_get(
  181. boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
  182. BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
  183. ) BOOST_NOEXCEPT
  184. {
  185. BOOST_STATIC_ASSERT_MSG(
  186. (boost::detail::variant::holds_element_polymorphic<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, U >::value),
  187. "boost::variant does not contain specified type U, "
  188. "call to boost::polymorphic_get<U>(boost::variant<T...>*) will always return NULL"
  189. );
  190. return polymorphic_relaxed_get<U>(operand);
  191. }
  192. template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
  193. inline
  194. typename add_pointer<const U>::type
  195. polymorphic_strict_get(
  196. const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
  197. BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
  198. ) BOOST_NOEXCEPT
  199. {
  200. BOOST_STATIC_ASSERT_MSG(
  201. (boost::detail::variant::holds_element_polymorphic<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, U >::value),
  202. "boost::variant does not contain specified type U, "
  203. "call to boost::polymorphic_get<U>(const boost::variant<T...>*) will always return NULL"
  204. );
  205. return polymorphic_relaxed_get<U>(operand);
  206. }
  207. template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
  208. inline
  209. typename add_reference<U>::type
  210. polymorphic_strict_get(
  211. boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
  212. BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
  213. )
  214. {
  215. BOOST_STATIC_ASSERT_MSG(
  216. (boost::detail::variant::holds_element_polymorphic<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, U >::value),
  217. "boost::variant does not contain specified type U, "
  218. "call to boost::polymorphic_get<U>(boost::variant<T...>&) will always throw boost::bad_polymorphic_get exception"
  219. );
  220. return polymorphic_relaxed_get<U>(operand);
  221. }
  222. template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
  223. inline
  224. typename add_reference<const U>::type
  225. polymorphic_strict_get(
  226. const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
  227. BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
  228. )
  229. {
  230. BOOST_STATIC_ASSERT_MSG(
  231. (boost::detail::variant::holds_element_polymorphic<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, U >::value),
  232. "boost::variant does not contain specified type U, "
  233. "call to boost::polymorphic_get<U>(const boost::variant<T...>&) will always throw boost::bad_polymorphic_get exception"
  234. );
  235. return polymorphic_relaxed_get<U>(operand);
  236. }
  237. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  238. // polymorphic_get<U>(variant) methods
  239. //
  240. template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
  241. inline
  242. typename add_pointer<U>::type
  243. polymorphic_get(
  244. boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
  245. BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
  246. ) BOOST_NOEXCEPT
  247. {
  248. #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT
  249. return polymorphic_relaxed_get<U>(operand);
  250. #else
  251. return polymorphic_strict_get<U>(operand);
  252. #endif
  253. }
  254. template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
  255. inline
  256. typename add_pointer<const U>::type
  257. polymorphic_get(
  258. const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
  259. BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
  260. ) BOOST_NOEXCEPT
  261. {
  262. #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT
  263. return polymorphic_relaxed_get<U>(operand);
  264. #else
  265. return polymorphic_strict_get<U>(operand);
  266. #endif
  267. }
  268. template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
  269. inline
  270. typename add_reference<U>::type
  271. polymorphic_get(
  272. boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
  273. BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
  274. )
  275. {
  276. #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT
  277. return polymorphic_relaxed_get<U>(operand);
  278. #else
  279. return polymorphic_strict_get<U>(operand);
  280. #endif
  281. }
  282. template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
  283. inline
  284. typename add_reference<const U>::type
  285. polymorphic_get(
  286. const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
  287. BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
  288. )
  289. {
  290. #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT
  291. return polymorphic_relaxed_get<U>(operand);
  292. #else
  293. return polymorphic_strict_get<U>(operand);
  294. #endif
  295. }
  296. } // namespace boost
  297. #endif // BOOST_VARIANT_POLYMORPHIC_GET_HPP