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