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