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 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     virtual const char * what() const BOOST_NOEXCEPT_OR_NOTHROW
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(__BORLANDC__, BOOST_TESTED_AT(0x0551))
103 #       define BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(t)
104 #   else
105 #       define BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(t)  \
106         , t* = 0
107 #   endif
108 #endif
109 
110 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
111 // relaxed_get<U>(variant) methods
112 //
113 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
114 inline
115     typename add_pointer<U>::type
relaxed_get(boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> * operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))116 relaxed_get(
117       boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
118       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
119     ) BOOST_NOEXCEPT
120 {
121     typedef typename add_pointer<U>::type U_ptr;
122     if (!operand) return static_cast<U_ptr>(0);
123 
124     detail::variant::get_visitor<U> v;
125     return operand->apply_visitor(v);
126 }
127 
128 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
129 inline
130     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))131 relaxed_get(
132       const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
133       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
134     ) BOOST_NOEXCEPT
135 {
136     typedef typename add_pointer<const U>::type U_ptr;
137     if (!operand) return static_cast<U_ptr>(0);
138 
139     detail::variant::get_visitor<const U> v;
140     return operand->apply_visitor(v);
141 }
142 
143 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
144 inline
145     typename add_reference<U>::type
relaxed_get(boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> & operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))146 relaxed_get(
147       boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
148       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
149     )
150 {
151     typedef typename add_pointer<U>::type U_ptr;
152     U_ptr result = relaxed_get<U>(boost::addressof(operand));
153 
154     if (!result)
155         boost::throw_exception(bad_get());
156     return *result;
157 }
158 
159 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
160 inline
161     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))162 relaxed_get(
163       const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
164       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
165     )
166 {
167     typedef typename add_pointer<const U>::type U_ptr;
168     U_ptr result = relaxed_get<const U>(boost::addressof(operand));
169 
170     if (!result)
171         boost::throw_exception(bad_get());
172     return *result;
173 }
174 
175 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
176 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
177 inline
178     U&&
relaxed_get(boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> && operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))179 relaxed_get(
180       boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >&& operand
181       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
182     )
183 {
184     typedef typename add_pointer<U>::type U_ptr;
185     U_ptr result = relaxed_get<U>(boost::addressof(operand));
186 
187     if (!result)
188         boost::throw_exception(bad_get());
189     return static_cast<U&&>(*result);
190 }
191 #endif
192 
193 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
194 // strict_get<U>(variant) methods
195 //
196 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
197 inline
198     typename add_pointer<U>::type
strict_get(boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> * operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))199 strict_get(
200       boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
201       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
202     ) BOOST_NOEXCEPT
203 {
204     BOOST_STATIC_ASSERT_MSG(
205         (boost::detail::variant::holds_element<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, U >::value),
206         "boost::variant does not contain specified type U, "
207         "call to boost::get<U>(boost::variant<T...>*) will always return NULL"
208     );
209 
210     return relaxed_get<U>(operand);
211 }
212 
213 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
214 inline
215     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))216 strict_get(
217       const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
218       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
219     ) BOOST_NOEXCEPT
220 {
221     BOOST_STATIC_ASSERT_MSG(
222         (boost::detail::variant::holds_element<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, const U >::value),
223         "boost::variant does not contain specified type U, "
224         "call to boost::get<U>(const boost::variant<T...>*) will always return NULL"
225     );
226 
227     return relaxed_get<U>(operand);
228 }
229 
230 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
231 inline
232     typename add_reference<U>::type
strict_get(boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> & operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))233 strict_get(
234       boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
235       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
236     )
237 {
238     BOOST_STATIC_ASSERT_MSG(
239         (boost::detail::variant::holds_element<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, U >::value),
240         "boost::variant does not contain specified type U, "
241         "call to boost::get<U>(boost::variant<T...>&) will always throw boost::bad_get exception"
242     );
243 
244     return relaxed_get<U>(operand);
245 }
246 
247 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
248 inline
249     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))250 strict_get(
251       const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
252       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
253     )
254 {
255     BOOST_STATIC_ASSERT_MSG(
256         (boost::detail::variant::holds_element<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, const U >::value),
257         "boost::variant does not contain specified type U, "
258         "call to boost::get<U>(const boost::variant<T...>&) will always throw boost::bad_get exception"
259     );
260 
261     return relaxed_get<U>(operand);
262 }
263 
264 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
265 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
266 inline
267     U&&
strict_get(boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> && operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))268 strict_get(
269       boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >&& operand
270       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
271     )
272 {
273     BOOST_STATIC_ASSERT_MSG(
274         (!boost::is_lvalue_reference<U>::value),
275         "remove ampersand '&' from template type U in boost::get<U>(boost::variant<T...>&&) "
276     );
277 
278     BOOST_STATIC_ASSERT_MSG(
279         (boost::detail::variant::holds_element<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, U >::value),
280         "boost::variant does not contain specified type U, "
281         "call to boost::get<U>(const boost::variant<T...>&) will always throw boost::bad_get exception"
282     );
283 
284     return relaxed_get<U>(detail::variant::move(operand));
285 }
286 #endif
287 
288 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
289 // get<U>(variant) methods
290 //
291 
292 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
293 inline
294     typename add_pointer<U>::type
get(boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> * operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))295 get(
296       boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
297       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
298     ) BOOST_NOEXCEPT
299 {
300 #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT
301     return relaxed_get<U>(operand);
302 #else
303     return strict_get<U>(operand);
304 #endif
305 
306 }
307 
308 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
309 inline
310     typename add_pointer<const U>::type
get(const boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> * operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))311 get(
312       const 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 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
324 inline
325     typename add_reference<U>::type
get(boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> & operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))326 get(
327       boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
328       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
329     )
330 {
331 #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT
332     return relaxed_get<U>(operand);
333 #else
334     return strict_get<U>(operand);
335 #endif
336 }
337 
338 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
339 inline
340     typename add_reference<const U>::type
get(const boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> & operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))341 get(
342       const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
343       BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
344     )
345 {
346 #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT
347     return relaxed_get<U>(operand);
348 #else
349     return strict_get<U>(operand);
350 #endif
351 }
352 
353 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
354 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
355 inline
356     U&&
get(boost::variant<BOOST_VARIANT_ENUM_PARAMS (T)> && operand BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE (U))357 get(
358       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>(detail::variant::move(operand));
364 #else
365     return strict_get<U>(detail::variant::move(operand));
366 #endif
367 }
368 #endif
369 
370 } // namespace boost
371 
372 #endif // BOOST_VARIANT_GET_HPP
373