]>
Commit | Line | Data |
---|---|---|
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-2023 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/core/addressof.hpp> | |
19 | #include <boost/detail/workaround.hpp> | |
20 | #include <boost/static_assert.hpp> | |
21 | #include <boost/throw_exception.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 | ||
42 | 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 | ||
100 | pointer get(reference operand, boost::true_type) const BOOST_NOEXCEPT | |
101 | { | |
102 | return boost::addressof(operand); | |
103 | } | |
104 | ||
105 | template <class T> | |
106 | 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> | |
115 | 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_CXX11_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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 |