• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //-----------------------------------------------------------------------------
2 // boost variant/get.hpp header file
3 // See http://www.boost.org for updates, documentation, and revision history.
4 //-----------------------------------------------------------------------------
5 //
6 // Copyright (c) 2003 Eric Friedman, Itay Maman
7 // Copyright (c) 2014-2020 Antony Polukhin
8 //
9 // Distributed under the Boost Software License, Version 1.0. (See
10 // accompanying file LICENSE_1_0.txt or copy at
11 // http://www.boost.org/LICENSE_1_0.txt)
12 
13 #ifndef BOOST_VARIANT_GET_HPP
14 #define BOOST_VARIANT_GET_HPP
15 
16 #include <exception>
17 
18 #include <boost/config.hpp>
19 #include <boost/detail/workaround.hpp>
20 #include <boost/static_assert.hpp>
21 #include <boost/throw_exception.hpp>
22 #include <boost/utility/addressof.hpp>
23 #include <boost/variant/variant_fwd.hpp>
24 #include <boost/variant/detail/element_index.hpp>
25 #include <boost/variant/detail/move.hpp>
26 
27 #include <boost/type_traits/add_reference.hpp>
28 #include <boost/type_traits/add_pointer.hpp>
29 #include <boost/type_traits/is_lvalue_reference.hpp>
30 
31 namespace boost {
32 
33 #if defined(BOOST_CLANG)
34 #   pragma clang diagnostic push
35 #   pragma clang diagnostic ignored "-Wweak-vtables"
36 #endif
37 //////////////////////////////////////////////////////////////////////////
38 // class bad_get
39 //
40 // The exception thrown in the event of a failed get of a value.
41 //
42 class BOOST_SYMBOL_VISIBLE bad_get
43     : public std::exception
44 {
45 public: // std::exception implementation
46 
what() const47     const char * what() const BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE
48     {
49         return "boost::bad_get: "
50                "failed value get using boost::get";
51     }
52 
53 };
54 #if defined(BOOST_CLANG)
55 #   pragma clang diagnostic pop
56 #endif
57 
58 
59 //////////////////////////////////////////////////////////////////////////
60 // function template get<T>
61 //
62 // Retrieves content of given variant object if content is of type T.
63 // Otherwise: pointer ver. returns 0; reference ver. throws bad_get.
64 //
65 
66 namespace detail { namespace variant {
67 
68 // (detail) class template get_visitor
69 //
70 // Generic static visitor that: if the value is of the specified type,
71 // returns a pointer to the value it visits; else a null pointer.
72 //
73 template <typename T>
74 struct get_visitor
75 {
76 private: // private typedefs
77 
78     typedef typename add_pointer<T>::type pointer;
79     typedef typename add_reference<T>::type reference;
80 
81 public: // visitor typedefs
82 
83     typedef pointer result_type;
84 
85 public: // visitor interfaces
86 
operator ()boost::detail::variant::get_visitor87     pointer operator()(reference operand) const BOOST_NOEXCEPT
88     {
89         return boost::addressof(operand);
90     }
91 
92     template <typename U>
operator ()boost::detail::variant::get_visitor93     pointer operator()(const U&) const BOOST_NOEXCEPT
94     {
95         return static_cast<pointer>(0);
96     }
97 };
98 
99 }} // namespace detail::variant
100 
101 #ifndef BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE
102 #   if !BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x0551))
103 #       define BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(t)
104 #   else
105 #       if defined(BOOST_NO_NULLPTR)
106 #           define BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(t)  \
107             , t* = 0
108 #       else
109 #           define BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(t)  \
110             , t* = nullptr
111 #       endif
112 #   endif
113 #endif
114 
115 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
116 // relaxed_get<U>(variant) methods
117 //
118 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
119 inline
120     typename add_pointer<U>::type
relaxed_get(boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> * operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))121 relaxed_get(
122       boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
123       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
124     ) BOOST_NOEXCEPT
125 {
126     typedef typename add_pointer<U>::type U_ptr;
127     if (!operand) return static_cast<U_ptr>(0);
128 
129     detail::variant::get_visitor<U> v;
130     return operand->apply_visitor(v);
131 }
132 
133 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
134 inline
135     typename add_pointer<const U>::type
relaxed_get(const boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> * operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))136 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 
144     detail::variant::get_visitor<const U> v;
145     return operand->apply_visitor(v);
146 }
147 
148 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
149 inline
150     typename add_reference<U>::type
relaxed_get(boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> & operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))151 relaxed_get(
152       boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
153       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
154     )
155 {
156     typedef typename add_pointer<U>::type U_ptr;
157     U_ptr result = relaxed_get<U>(boost::addressof(operand));
158 
159     if (!result)
160         boost::throw_exception(bad_get());
161     return *result;
162 }
163 
164 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
165 inline
166     typename add_reference<const U>::type
relaxed_get(const boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> & operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))167 relaxed_get(
168       const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
169       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
170     )
171 {
172     typedef typename add_pointer<const U>::type U_ptr;
173     U_ptr result = relaxed_get<const U>(boost::addressof(operand));
174 
175     if (!result)
176         boost::throw_exception(bad_get());
177     return *result;
178 }
179 
180 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
181 
182 #if defined(BOOST_MSVC) && (_MSC_VER < 1900) // MSVC-2014 has fixed the incorrect diagnostics.
183 #   pragma warning(push)
184 #   pragma warning(disable: 4172) // returning address of local variable or temporary
185 #endif
186 
187 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
188 inline
189     U&&
relaxed_get(boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> && operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))190 relaxed_get(
191       boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >&& operand
192       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
193     )
194 {
195     typedef typename add_pointer<U>::type U_ptr;
196     U_ptr result = relaxed_get<U>(boost::addressof(operand));
197 
198     if (!result)
199         boost::throw_exception(bad_get());
200     return static_cast<U&&>(*result);
201 }
202 
203 #if defined(BOOST_MSVC) && (_MSC_VER < 1900)
204 #   pragma warning(pop)
205 #endif
206 
207 #endif
208 
209 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
210 // strict_get<U>(variant) methods
211 //
212 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
213 inline
214     typename add_pointer<U>::type
strict_get(boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> * operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))215 strict_get(
216       boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
217       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
218     ) BOOST_NOEXCEPT
219 {
220     BOOST_STATIC_ASSERT_MSG(
221         (boost::detail::variant::holds_element<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, U >::value),
222         "boost::variant does not contain specified type U, "
223         "call to boost::get<U>(boost::variant<T...>*) will always return NULL"
224     );
225 
226     return relaxed_get<U>(operand);
227 }
228 
229 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
230 inline
231     typename add_pointer<const U>::type
strict_get(const boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> * operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))232 strict_get(
233       const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
234       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
235     ) BOOST_NOEXCEPT
236 {
237     BOOST_STATIC_ASSERT_MSG(
238         (boost::detail::variant::holds_element<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, const U >::value),
239         "boost::variant does not contain specified type U, "
240         "call to boost::get<U>(const boost::variant<T...>*) will always return NULL"
241     );
242 
243     return relaxed_get<U>(operand);
244 }
245 
246 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
247 inline
248     typename add_reference<U>::type
strict_get(boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> & operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))249 strict_get(
250       boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
251       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
252     )
253 {
254     BOOST_STATIC_ASSERT_MSG(
255         (boost::detail::variant::holds_element<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, U >::value),
256         "boost::variant does not contain specified type U, "
257         "call to boost::get<U>(boost::variant<T...>&) will always throw boost::bad_get exception"
258     );
259 
260     return relaxed_get<U>(operand);
261 }
262 
263 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
264 inline
265     typename add_reference<const U>::type
strict_get(const boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> & operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))266 strict_get(
267       const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
268       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
269     )
270 {
271     BOOST_STATIC_ASSERT_MSG(
272         (boost::detail::variant::holds_element<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, const U >::value),
273         "boost::variant does not contain specified type U, "
274         "call to boost::get<U>(const boost::variant<T...>&) will always throw boost::bad_get exception"
275     );
276 
277     return relaxed_get<U>(operand);
278 }
279 
280 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
281 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
282 inline
283     U&&
strict_get(boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> && operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))284 strict_get(
285       boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >&& operand
286       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
287     )
288 {
289     BOOST_STATIC_ASSERT_MSG(
290         (!boost::is_lvalue_reference<U>::value),
291         "remove ampersand '&' from template type U in boost::get<U>(boost::variant<T...>&&) "
292     );
293 
294     BOOST_STATIC_ASSERT_MSG(
295         (boost::detail::variant::holds_element<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, U >::value),
296         "boost::variant does not contain specified type U, "
297         "call to boost::get<U>(const boost::variant<T...>&) will always throw boost::bad_get exception"
298     );
299 
300     return relaxed_get<U>(detail::variant::move(operand));
301 }
302 #endif
303 
304 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
305 // get<U>(variant) methods
306 //
307 
308 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
309 inline
310     typename add_pointer<U>::type
get(boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> * operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))311 get(
312       boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
313       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
314     ) BOOST_NOEXCEPT
315 {
316 #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT
317     return relaxed_get<U>(operand);
318 #else
319     return strict_get<U>(operand);
320 #endif
321 
322 }
323 
324 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
325 inline
326     typename add_pointer<const U>::type
get(const boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> * operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))327 get(
328       const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
329       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
330     ) BOOST_NOEXCEPT
331 {
332 #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT
333     return relaxed_get<U>(operand);
334 #else
335     return strict_get<U>(operand);
336 #endif
337 }
338 
339 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
340 inline
341     typename add_reference<U>::type
get(boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> & operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))342 get(
343       boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
344       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
345     )
346 {
347 #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT
348     return relaxed_get<U>(operand);
349 #else
350     return strict_get<U>(operand);
351 #endif
352 }
353 
354 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
355 inline
356     typename add_reference<const U>::type
get(const boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> & operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))357 get(
358       const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
359       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
360     )
361 {
362 #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT
363     return relaxed_get<U>(operand);
364 #else
365     return strict_get<U>(operand);
366 #endif
367 }
368 
369 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
370 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
371 inline
372     U&&
get(boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> && operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))373 get(
374       boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >&& operand
375       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
376     )
377 {
378 #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT
379     return relaxed_get<U>(detail::variant::move(operand));
380 #else
381     return strict_get<U>(detail::variant::move(operand));
382 #endif
383 }
384 #endif
385 
386 } // namespace boost
387 
388 #endif // BOOST_VARIANT_GET_HPP
389