polymorphic_get.hpp 11 KB

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