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