blob: 37c736de61c6e082583070b82120b2feab15294b [file] [log] [blame]
Patrick Williamsceefb312016-09-11 21:12:42 -05001#ifndef MAPBOX_UTIL_VARIANT_HPP
2#define MAPBOX_UTIL_VARIANT_HPP
3
4#include <cassert>
5#include <cstddef> // size_t
6#include <new> // operator new
7#include <stdexcept> // runtime_error
8#include <string>
9#include <tuple>
10#include <type_traits>
11#include <typeinfo>
12#include <utility>
13
14#include <mapbox/recursive_wrapper.hpp>
15
16// clang-format off
17// [[deprecated]] is only available in C++14, use this for the time being
18#if __cplusplus <= 201103L
19# ifdef __GNUC__
20# define MAPBOX_VARIANT_DEPRECATED __attribute__((deprecated))
21# elif defined(_MSC_VER)
22# define MAPBOX_VARIANT_DEPRECATED __declspec(deprecated)
23# else
24# define MAPBOX_VARIANT_DEPRECATED
25# endif
26#else
27# define MAPBOX_VARIANT_DEPRECATED [[deprecated]]
28#endif
29
30
31#ifdef _MSC_VER
32// https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx
33# ifdef NDEBUG
34# define VARIANT_INLINE __forceinline
35# else
36# define VARIANT_INLINE //__declspec(noinline)
37# endif
38#else
39# ifdef NDEBUG
40# define VARIANT_INLINE //inline __attribute__((always_inline))
41# else
42# define VARIANT_INLINE __attribute__((noinline))
43# endif
44#endif
45// clang-format on
46
47// Exceptions
Andrew Geissler072da3e2018-01-18 07:21:42 -080048#if defined(__EXCEPTIONS) || defined(_MSC_VER)
Patrick Williamsceefb312016-09-11 21:12:42 -050049#define HAS_EXCEPTIONS
50#endif
51
52#define VARIANT_MAJOR_VERSION 1
53#define VARIANT_MINOR_VERSION 1
54#define VARIANT_PATCH_VERSION 0
55
Andrew Geissler072da3e2018-01-18 07:21:42 -080056#define VARIANT_VERSION \
57 (VARIANT_MAJOR_VERSION * 100000) + (VARIANT_MINOR_VERSION * 100) + \
58 (VARIANT_PATCH_VERSION)
Patrick Williamsceefb312016-09-11 21:12:42 -050059
Andrew Geissler072da3e2018-01-18 07:21:42 -080060namespace mapbox
61{
62namespace util
63{
Patrick Williamsceefb312016-09-11 21:12:42 -050064
65// XXX This should derive from std::logic_error instead of std::runtime_error.
66// See https://github.com/mapbox/variant/issues/48 for details.
67class bad_variant_access : public std::runtime_error
68{
69
Andrew Geissler072da3e2018-01-18 07:21:42 -080070 public:
71 explicit bad_variant_access(const std::string& what_arg) :
72 runtime_error(what_arg)
73 {
74 }
Patrick Williamsceefb312016-09-11 21:12:42 -050075
Andrew Geissler072da3e2018-01-18 07:21:42 -080076 explicit bad_variant_access(const char* what_arg) : runtime_error(what_arg)
77 {
78 }
Patrick Williamsceefb312016-09-11 21:12:42 -050079
80}; // class bad_variant_access
81
Andrew Geissler072da3e2018-01-18 07:21:42 -080082template <typename R = void> struct MAPBOX_VARIANT_DEPRECATED static_visitor
Patrick Williamsceefb312016-09-11 21:12:42 -050083{
84 using result_type = R;
85
Andrew Geissler072da3e2018-01-18 07:21:42 -080086 protected:
87 static_visitor()
88 {
89 }
90 ~static_visitor()
91 {
92 }
Patrick Williamsceefb312016-09-11 21:12:42 -050093};
94
Andrew Geissler072da3e2018-01-18 07:21:42 -080095namespace detail
96{
Patrick Williamsceefb312016-09-11 21:12:42 -050097
98static constexpr std::size_t invalid_value = std::size_t(-1);
99
Andrew Geissler072da3e2018-01-18 07:21:42 -0800100template <typename T, typename... Types> struct direct_type;
Patrick Williamsceefb312016-09-11 21:12:42 -0500101
102template <typename T, typename First, typename... Types>
103struct direct_type<T, First, Types...>
104{
105 static constexpr std::size_t index = std::is_same<T, First>::value
Andrew Geissler072da3e2018-01-18 07:21:42 -0800106 ? sizeof...(Types)
107 : direct_type<T, Types...>::index;
Patrick Williamsceefb312016-09-11 21:12:42 -0500108};
109
Andrew Geissler072da3e2018-01-18 07:21:42 -0800110template <typename T> struct direct_type<T>
Patrick Williamsceefb312016-09-11 21:12:42 -0500111{
112 static constexpr std::size_t index = invalid_value;
113};
114
115#if __cpp_lib_logical_traits >= 201510L
116
117using std::disjunction;
118
119#else
120
Andrew Geissler072da3e2018-01-18 07:21:42 -0800121template <typename...> struct disjunction : std::false_type
122{
123};
Patrick Williamsceefb312016-09-11 21:12:42 -0500124
Andrew Geissler072da3e2018-01-18 07:21:42 -0800125template <typename B1> struct disjunction<B1> : B1
126{
127};
Patrick Williamsceefb312016-09-11 21:12:42 -0500128
129template <typename B1, typename B2>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800130struct disjunction<B1, B2> : std::conditional<B1::value, B1, B2>::type
131{
132};
Patrick Williamsceefb312016-09-11 21:12:42 -0500133
134template <typename B1, typename... Bs>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800135struct disjunction<B1, Bs...>
136 : std::conditional<B1::value, B1, disjunction<Bs...>>::type
137{
138};
Patrick Williamsceefb312016-09-11 21:12:42 -0500139
140#endif
141
Andrew Geissler072da3e2018-01-18 07:21:42 -0800142template <typename T, typename... Types> struct convertible_type;
Patrick Williamsceefb312016-09-11 21:12:42 -0500143
144template <typename T, typename First, typename... Types>
145struct convertible_type<T, First, Types...>
146{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800147 static constexpr std::size_t index =
148 std::is_convertible<T, First>::value
149 ? disjunction<std::is_convertible<T, Types>...>::value
150 ? invalid_value
151 : sizeof...(Types)
152 : convertible_type<T, Types...>::index;
Patrick Williamsceefb312016-09-11 21:12:42 -0500153};
154
Andrew Geissler072da3e2018-01-18 07:21:42 -0800155template <typename T> struct convertible_type<T>
Patrick Williamsceefb312016-09-11 21:12:42 -0500156{
157 static constexpr std::size_t index = invalid_value;
158};
159
Andrew Geissler072da3e2018-01-18 07:21:42 -0800160template <typename T, typename... Types> struct value_traits
Patrick Williamsceefb312016-09-11 21:12:42 -0500161{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800162 using value_type = typename std::remove_const<
163 typename std::remove_reference<T>::type>::type;
164 static constexpr std::size_t direct_index =
165 direct_type<value_type, Types...>::index;
Patrick Williamsceefb312016-09-11 21:12:42 -0500166 static constexpr bool is_direct = direct_index != invalid_value;
Andrew Geissler072da3e2018-01-18 07:21:42 -0800167 static constexpr std::size_t index =
168 is_direct ? direct_index
169 : convertible_type<value_type, Types...>::index;
Patrick Williamsceefb312016-09-11 21:12:42 -0500170 static constexpr bool is_valid = index != invalid_value;
Andrew Geissler072da3e2018-01-18 07:21:42 -0800171 static constexpr std::size_t tindex =
172 is_valid ? sizeof...(Types) - index : 0;
173 using target_type =
174 typename std::tuple_element<tindex, std::tuple<void, Types...>>::type;
Patrick Williamsceefb312016-09-11 21:12:42 -0500175};
176
Andrew Geissler072da3e2018-01-18 07:21:42 -0800177template <typename T, typename R = void> struct enable_if_type
Patrick Williamsceefb312016-09-11 21:12:42 -0500178{
179 using type = R;
180};
181
182template <typename F, typename V, typename Enable = void>
183struct result_of_unary_visit
184{
185 using type = typename std::result_of<F(V&)>::type;
186};
187
188template <typename F, typename V>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800189struct result_of_unary_visit<
190 F, V, typename enable_if_type<typename F::result_type>::type>
Patrick Williamsceefb312016-09-11 21:12:42 -0500191{
192 using type = typename F::result_type;
193};
194
195template <typename F, typename V, typename Enable = void>
196struct result_of_binary_visit
197{
198 using type = typename std::result_of<F(V&, V&)>::type;
199};
200
201template <typename F, typename V>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800202struct result_of_binary_visit<
203 F, V, typename enable_if_type<typename F::result_type>::type>
Patrick Williamsceefb312016-09-11 21:12:42 -0500204{
205 using type = typename F::result_type;
206};
207
Andrew Geissler072da3e2018-01-18 07:21:42 -0800208template <std::size_t arg1, std::size_t... others> struct static_max;
Patrick Williamsceefb312016-09-11 21:12:42 -0500209
Andrew Geissler072da3e2018-01-18 07:21:42 -0800210template <std::size_t arg> struct static_max<arg>
Patrick Williamsceefb312016-09-11 21:12:42 -0500211{
212 static const std::size_t value = arg;
213};
214
215template <std::size_t arg1, std::size_t arg2, std::size_t... others>
216struct static_max<arg1, arg2, others...>
217{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800218 static const std::size_t value = arg1 >= arg2
219 ? static_max<arg1, others...>::value
220 : static_max<arg2, others...>::value;
Patrick Williamsceefb312016-09-11 21:12:42 -0500221};
222
Andrew Geissler072da3e2018-01-18 07:21:42 -0800223template <typename... Types> struct variant_helper;
Patrick Williamsceefb312016-09-11 21:12:42 -0500224
Andrew Geissler072da3e2018-01-18 07:21:42 -0800225template <typename T, typename... Types> struct variant_helper<T, Types...>
Patrick Williamsceefb312016-09-11 21:12:42 -0500226{
227 VARIANT_INLINE static void destroy(const std::size_t type_index, void* data)
228 {
229 if (type_index == sizeof...(Types))
230 {
231 reinterpret_cast<T*>(data)->~T();
232 }
233 else
234 {
235 variant_helper<Types...>::destroy(type_index, data);
236 }
237 }
238
Andrew Geissler072da3e2018-01-18 07:21:42 -0800239 VARIANT_INLINE static void move(const std::size_t old_type_index,
240 void* old_value, void* new_value)
Patrick Williamsceefb312016-09-11 21:12:42 -0500241 {
242 if (old_type_index == sizeof...(Types))
243 {
244 new (new_value) T(std::move(*reinterpret_cast<T*>(old_value)));
245 }
246 else
247 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800248 variant_helper<Types...>::move(old_type_index, old_value,
249 new_value);
Patrick Williamsceefb312016-09-11 21:12:42 -0500250 }
251 }
252
Andrew Geissler072da3e2018-01-18 07:21:42 -0800253 VARIANT_INLINE static void copy(const std::size_t old_type_index,
254 const void* old_value, void* new_value)
Patrick Williamsceefb312016-09-11 21:12:42 -0500255 {
256 if (old_type_index == sizeof...(Types))
257 {
258 new (new_value) T(*reinterpret_cast<const T*>(old_value));
259 }
260 else
261 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800262 variant_helper<Types...>::copy(old_type_index, old_value,
263 new_value);
Patrick Williamsceefb312016-09-11 21:12:42 -0500264 }
265 }
266};
267
Andrew Geissler072da3e2018-01-18 07:21:42 -0800268template <> struct variant_helper<>
Patrick Williamsceefb312016-09-11 21:12:42 -0500269{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800270 VARIANT_INLINE static void destroy(const std::size_t, void*)
271 {
272 }
273 VARIANT_INLINE static void move(const std::size_t, void*, void*)
274 {
275 }
276 VARIANT_INLINE static void copy(const std::size_t, const void*, void*)
277 {
278 }
Patrick Williamsceefb312016-09-11 21:12:42 -0500279};
280
Andrew Geissler072da3e2018-01-18 07:21:42 -0800281template <typename T> struct unwrapper
Patrick Williamsceefb312016-09-11 21:12:42 -0500282{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800283 static T const& apply_const(T const& obj)
284 {
285 return obj;
286 }
287 static T& apply(T& obj)
288 {
289 return obj;
290 }
Patrick Williamsceefb312016-09-11 21:12:42 -0500291};
292
Andrew Geissler072da3e2018-01-18 07:21:42 -0800293template <typename T> struct unwrapper<recursive_wrapper<T>>
Patrick Williamsceefb312016-09-11 21:12:42 -0500294{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800295 static auto apply_const(recursive_wrapper<T> const& obj) ->
296 typename recursive_wrapper<T>::type const&
Patrick Williamsceefb312016-09-11 21:12:42 -0500297 {
298 return obj.get();
299 }
Andrew Geissler072da3e2018-01-18 07:21:42 -0800300 static auto apply(recursive_wrapper<T>& obj) ->
301 typename recursive_wrapper<T>::type&
Patrick Williamsceefb312016-09-11 21:12:42 -0500302 {
303 return obj.get();
304 }
305};
306
Andrew Geissler072da3e2018-01-18 07:21:42 -0800307template <typename T> struct unwrapper<std::reference_wrapper<T>>
Patrick Williamsceefb312016-09-11 21:12:42 -0500308{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800309 static auto apply_const(std::reference_wrapper<T> const& obj) ->
310 typename std::reference_wrapper<T>::type const&
Patrick Williamsceefb312016-09-11 21:12:42 -0500311 {
312 return obj.get();
313 }
Andrew Geissler072da3e2018-01-18 07:21:42 -0800314 static auto apply(std::reference_wrapper<T>& obj) ->
315 typename std::reference_wrapper<T>::type&
Patrick Williamsceefb312016-09-11 21:12:42 -0500316 {
317 return obj.get();
318 }
319};
320
321template <typename F, typename V, typename R, typename... Types>
322struct dispatcher;
323
324template <typename F, typename V, typename R, typename T, typename... Types>
325struct dispatcher<F, V, R, T, Types...>
326{
327 VARIANT_INLINE static R apply_const(V const& v, F&& f)
328 {
329 if (v.template is<T>())
330 {
331 return f(unwrapper<T>::apply_const(v.template get_unchecked<T>()));
332 }
333 else
334 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800335 return dispatcher<F, V, R, Types...>::apply_const(
336 v, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500337 }
338 }
339
340 VARIANT_INLINE static R apply(V& v, F&& f)
341 {
342 if (v.template is<T>())
343 {
344 return f(unwrapper<T>::apply(v.template get_unchecked<T>()));
345 }
346 else
347 {
348 return dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
349 }
350 }
351};
352
353template <typename F, typename V, typename R, typename T>
354struct dispatcher<F, V, R, T>
355{
356 VARIANT_INLINE static R apply_const(V const& v, F&& f)
357 {
358 return f(unwrapper<T>::apply_const(v.template get_unchecked<T>()));
359 }
360
361 VARIANT_INLINE static R apply(V& v, F&& f)
362 {
363 return f(unwrapper<T>::apply(v.template get_unchecked<T>()));
364 }
365};
366
367template <typename F, typename V, typename R, typename T, typename... Types>
368struct binary_dispatcher_rhs;
369
Andrew Geissler072da3e2018-01-18 07:21:42 -0800370template <typename F, typename V, typename R, typename T0, typename T1,
371 typename... Types>
Patrick Williamsceefb312016-09-11 21:12:42 -0500372struct binary_dispatcher_rhs<F, V, R, T0, T1, Types...>
373{
374 VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
375 {
376 if (rhs.template is<T1>()) // call binary functor
377 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800378 return f(
379 unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()),
380 unwrapper<T1>::apply_const(rhs.template get_unchecked<T1>()));
Patrick Williamsceefb312016-09-11 21:12:42 -0500381 }
382 else
383 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800384 return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply_const(
385 lhs, rhs, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500386 }
387 }
388
389 VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
390 {
391 if (rhs.template is<T1>()) // call binary functor
392 {
393 return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()),
394 unwrapper<T1>::apply(rhs.template get_unchecked<T1>()));
395 }
396 else
397 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800398 return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply(
399 lhs, rhs, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500400 }
401 }
402};
403
404template <typename F, typename V, typename R, typename T0, typename T1>
405struct binary_dispatcher_rhs<F, V, R, T0, T1>
406{
407 VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
408 {
409 return f(unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()),
410 unwrapper<T1>::apply_const(rhs.template get_unchecked<T1>()));
411 }
412
413 VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
414 {
415 return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()),
416 unwrapper<T1>::apply(rhs.template get_unchecked<T1>()));
417 }
418};
419
420template <typename F, typename V, typename R, typename T, typename... Types>
421struct binary_dispatcher_lhs;
422
Andrew Geissler072da3e2018-01-18 07:21:42 -0800423template <typename F, typename V, typename R, typename T0, typename T1,
424 typename... Types>
Patrick Williamsceefb312016-09-11 21:12:42 -0500425struct binary_dispatcher_lhs<F, V, R, T0, T1, Types...>
426{
427 VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
428 {
429 if (lhs.template is<T1>()) // call binary functor
430 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800431 return f(
432 unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()),
433 unwrapper<T0>::apply_const(rhs.template get_unchecked<T0>()));
Patrick Williamsceefb312016-09-11 21:12:42 -0500434 }
435 else
436 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800437 return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply_const(
438 lhs, rhs, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500439 }
440 }
441
442 VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
443 {
444 if (lhs.template is<T1>()) // call binary functor
445 {
446 return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()),
447 unwrapper<T0>::apply(rhs.template get_unchecked<T0>()));
448 }
449 else
450 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800451 return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply(
452 lhs, rhs, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500453 }
454 }
455};
456
457template <typename F, typename V, typename R, typename T0, typename T1>
458struct binary_dispatcher_lhs<F, V, R, T0, T1>
459{
460 VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
461 {
462 return f(unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()),
463 unwrapper<T0>::apply_const(rhs.template get_unchecked<T0>()));
464 }
465
466 VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
467 {
468 return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()),
469 unwrapper<T0>::apply(rhs.template get_unchecked<T0>()));
470 }
471};
472
473template <typename F, typename V, typename R, typename... Types>
474struct binary_dispatcher;
475
476template <typename F, typename V, typename R, typename T, typename... Types>
477struct binary_dispatcher<F, V, R, T, Types...>
478{
479 VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
480 {
481 if (v0.template is<T>())
482 {
483 if (v1.template is<T>())
484 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800485 return f(
486 unwrapper<T>::apply_const(v0.template get_unchecked<T>()),
487 unwrapper<T>::apply_const(
488 v1.template get_unchecked<T>())); // call binary functor
Patrick Williamsceefb312016-09-11 21:12:42 -0500489 }
490 else
491 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800492 return binary_dispatcher_rhs<F, V, R, T, Types...>::apply_const(
493 v0, v1, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500494 }
495 }
496 else if (v1.template is<T>())
497 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800498 return binary_dispatcher_lhs<F, V, R, T, Types...>::apply_const(
499 v0, v1, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500500 }
Andrew Geissler072da3e2018-01-18 07:21:42 -0800501 return binary_dispatcher<F, V, R, Types...>::apply_const(
502 v0, v1, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500503 }
504
505 VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
506 {
507 if (v0.template is<T>())
508 {
509 if (v1.template is<T>())
510 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800511 return f(
512 unwrapper<T>::apply(v0.template get_unchecked<T>()),
513 unwrapper<T>::apply(
514 v1.template get_unchecked<T>())); // call binary functor
Patrick Williamsceefb312016-09-11 21:12:42 -0500515 }
516 else
517 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800518 return binary_dispatcher_rhs<F, V, R, T, Types...>::apply(
519 v0, v1, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500520 }
521 }
522 else if (v1.template is<T>())
523 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800524 return binary_dispatcher_lhs<F, V, R, T, Types...>::apply(
525 v0, v1, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500526 }
Andrew Geissler072da3e2018-01-18 07:21:42 -0800527 return binary_dispatcher<F, V, R, Types...>::apply(v0, v1,
528 std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500529 }
530};
531
532template <typename F, typename V, typename R, typename T>
533struct binary_dispatcher<F, V, R, T>
534{
535 VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
536 {
537 return f(unwrapper<T>::apply_const(v0.template get_unchecked<T>()),
Andrew Geissler072da3e2018-01-18 07:21:42 -0800538 unwrapper<T>::apply_const(
539 v1.template get_unchecked<T>())); // call binary functor
Patrick Williamsceefb312016-09-11 21:12:42 -0500540 }
541
542 VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
543 {
544 return f(unwrapper<T>::apply(v0.template get_unchecked<T>()),
Andrew Geissler072da3e2018-01-18 07:21:42 -0800545 unwrapper<T>::apply(
546 v1.template get_unchecked<T>())); // call binary functor
Patrick Williamsceefb312016-09-11 21:12:42 -0500547 }
548};
549
550// comparator functors
551struct equal_comp
552{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800553 template <typename T> bool operator()(T const& lhs, T const& rhs) const
Patrick Williamsceefb312016-09-11 21:12:42 -0500554 {
555 return lhs == rhs;
556 }
557};
558
559struct less_comp
560{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800561 template <typename T> bool operator()(T const& lhs, T const& rhs) const
Patrick Williamsceefb312016-09-11 21:12:42 -0500562 {
563 return lhs < rhs;
564 }
565};
566
Andrew Geissler072da3e2018-01-18 07:21:42 -0800567template <typename Variant, typename Comp> class comparer
Patrick Williamsceefb312016-09-11 21:12:42 -0500568{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800569 public:
570 explicit comparer(Variant const& lhs) noexcept : lhs_(lhs)
571 {
572 }
Patrick Williamsceefb312016-09-11 21:12:42 -0500573 comparer& operator=(comparer const&) = delete;
574 // visitor
Andrew Geissler072da3e2018-01-18 07:21:42 -0800575 template <typename T> bool operator()(T const& rhs_content) const
Patrick Williamsceefb312016-09-11 21:12:42 -0500576 {
577 T const& lhs_content = lhs_.template get_unchecked<T>();
578 return Comp()(lhs_content, rhs_content);
579 }
580
Andrew Geissler072da3e2018-01-18 07:21:42 -0800581 private:
Patrick Williamsceefb312016-09-11 21:12:42 -0500582 Variant const& lhs_;
583};
584
585} // namespace detail
586
587struct no_init
588{
589};
590
Andrew Geissler072da3e2018-01-18 07:21:42 -0800591template <typename... Types> class variant
Patrick Williamsceefb312016-09-11 21:12:42 -0500592{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800593 static_assert(sizeof...(Types) > 0,
594 "Template parameter type list of variant can not be empty");
595 static_assert(!detail::disjunction<std::is_reference<Types>...>::value,
596 "Variant can not hold reference types. Maybe use "
597 "std::reference_wrapper?");
Patrick Williamsceefb312016-09-11 21:12:42 -0500598
Andrew Geissler072da3e2018-01-18 07:21:42 -0800599 private:
600 static const std::size_t data_size =
601 detail::static_max<sizeof(Types)...>::value;
602 static const std::size_t data_align =
603 detail::static_max<alignof(Types)...>::value;
Patrick Williamsceefb312016-09-11 21:12:42 -0500604
Andrew Geissler072da3e2018-01-18 07:21:42 -0800605 using first_type =
606 typename std::tuple_element<0, std::tuple<Types...>>::type;
607 using data_type =
608 typename std::aligned_storage<data_size, data_align>::type;
Patrick Williamsceefb312016-09-11 21:12:42 -0500609 using helper_type = detail::variant_helper<Types...>;
610
611 std::size_t type_index;
612 data_type data;
613
Andrew Geissler072da3e2018-01-18 07:21:42 -0800614 public:
615 VARIANT_INLINE variant() noexcept(
616 std::is_nothrow_default_constructible<first_type>::value) :
617 type_index(sizeof...(Types) - 1)
Patrick Williamsceefb312016-09-11 21:12:42 -0500618 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800619 static_assert(std::is_default_constructible<first_type>::value,
620 "First type in variant must be default constructible to "
621 "allow default construction of variant");
Patrick Williamsceefb312016-09-11 21:12:42 -0500622 new (&data) first_type();
623 }
624
Andrew Geissler072da3e2018-01-18 07:21:42 -0800625 VARIANT_INLINE variant(no_init) noexcept : type_index(detail::invalid_value)
626 {
627 }
Patrick Williamsceefb312016-09-11 21:12:42 -0500628
629 // http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
630 template <typename T, typename Traits = detail::value_traits<T, Types...>,
631 typename Enable = typename std::enable_if<Traits::is_valid>::type>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800632 VARIANT_INLINE variant(T&& val) noexcept(
633 std::is_nothrow_constructible<typename Traits::target_type,
634 T&&>::value) :
635 type_index(Traits::index)
Patrick Williamsceefb312016-09-11 21:12:42 -0500636 {
637 new (&data) typename Traits::target_type(std::forward<T>(val));
638 }
639
Andrew Geissler072da3e2018-01-18 07:21:42 -0800640 VARIANT_INLINE variant(variant<Types...> const& old) :
641 type_index(old.type_index)
Patrick Williamsceefb312016-09-11 21:12:42 -0500642 {
643 helper_type::copy(old.type_index, &old.data, &data);
644 }
645
Andrew Geissler072da3e2018-01-18 07:21:42 -0800646 VARIANT_INLINE variant(variant<Types...>&& old) noexcept(
647 std::is_nothrow_move_constructible<std::tuple<Types...>>::value) :
648 type_index(old.type_index)
Patrick Williamsceefb312016-09-11 21:12:42 -0500649 {
650 helper_type::move(old.type_index, &old.data, &data);
651 }
652
Andrew Geissler072da3e2018-01-18 07:21:42 -0800653 private:
Patrick Williamsceefb312016-09-11 21:12:42 -0500654 VARIANT_INLINE void copy_assign(variant<Types...> const& rhs)
655 {
656 helper_type::destroy(type_index, &data);
657 type_index = detail::invalid_value;
658 helper_type::copy(rhs.type_index, &rhs.data, &data);
659 type_index = rhs.type_index;
660 }
661
662 VARIANT_INLINE void move_assign(variant<Types...>&& rhs)
663 {
664 helper_type::destroy(type_index, &data);
665 type_index = detail::invalid_value;
666 helper_type::move(rhs.type_index, &rhs.data, &data);
667 type_index = rhs.type_index;
668 }
669
Andrew Geissler072da3e2018-01-18 07:21:42 -0800670 public:
Patrick Williamsceefb312016-09-11 21:12:42 -0500671 VARIANT_INLINE variant<Types...>& operator=(variant<Types...>&& other)
672 {
673 move_assign(std::move(other));
674 return *this;
675 }
676
677 VARIANT_INLINE variant<Types...>& operator=(variant<Types...> const& other)
678 {
679 copy_assign(other);
680 return *this;
681 }
682
683 // conversions
684 // move-assign
685 template <typename T>
686 VARIANT_INLINE variant<Types...>& operator=(T&& rhs) noexcept
687 {
688 variant<Types...> temp(std::forward<T>(rhs));
689 move_assign(std::move(temp));
690 return *this;
691 }
692
693 // copy-assign
694 template <typename T>
695 VARIANT_INLINE variant<Types...>& operator=(T const& rhs)
696 {
697 variant<Types...> temp(rhs);
698 copy_assign(temp);
699 return *this;
700 }
701
702 template <typename T, typename std::enable_if<
Andrew Geissler072da3e2018-01-18 07:21:42 -0800703 (detail::direct_type<T, Types...>::index !=
704 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500705 VARIANT_INLINE bool is() const
706 {
707 return type_index == detail::direct_type<T, Types...>::index;
708 }
709
Andrew Geissler072da3e2018-01-18 07:21:42 -0800710 template <typename T,
711 typename std::enable_if<
712 (detail::direct_type<recursive_wrapper<T>, Types...>::index !=
713 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500714 VARIANT_INLINE bool is() const
715 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800716 return type_index ==
717 detail::direct_type<recursive_wrapper<T>, Types...>::index;
Patrick Williamsceefb312016-09-11 21:12:42 -0500718 }
719
720 VARIANT_INLINE bool valid() const
721 {
722 return type_index != detail::invalid_value;
723 }
724
725 template <typename T, typename... Args>
726 VARIANT_INLINE void set(Args&&... args)
727 {
728 helper_type::destroy(type_index, &data);
729 type_index = detail::invalid_value;
730 new (&data) T(std::forward<Args>(args)...);
731 type_index = detail::direct_type<T, Types...>::index;
732 }
733
734 // get_unchecked<T>()
735 template <typename T, typename std::enable_if<
Andrew Geissler072da3e2018-01-18 07:21:42 -0800736 (detail::direct_type<T, Types...>::index !=
737 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500738 VARIANT_INLINE T& get_unchecked()
739 {
740 return *reinterpret_cast<T*>(&data);
741 }
742
743#ifdef HAS_EXCEPTIONS
744 // get<T>()
745 template <typename T, typename std::enable_if<
Andrew Geissler072da3e2018-01-18 07:21:42 -0800746 (detail::direct_type<T, Types...>::index !=
747 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500748 VARIANT_INLINE T& get()
749 {
750 if (type_index == detail::direct_type<T, Types...>::index)
751 {
752 return *reinterpret_cast<T*>(&data);
753 }
754 else
755 {
756 throw bad_variant_access("in get<T>()");
757 }
758 }
759#endif
760
761 template <typename T, typename std::enable_if<
Andrew Geissler072da3e2018-01-18 07:21:42 -0800762 (detail::direct_type<T, Types...>::index !=
763 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500764 VARIANT_INLINE T const& get_unchecked() const
765 {
766 return *reinterpret_cast<T const*>(&data);
767 }
768
769#ifdef HAS_EXCEPTIONS
770 template <typename T, typename std::enable_if<
Andrew Geissler072da3e2018-01-18 07:21:42 -0800771 (detail::direct_type<T, Types...>::index !=
772 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500773 VARIANT_INLINE T const& get() const
774 {
775 if (type_index == detail::direct_type<T, Types...>::index)
776 {
777 return *reinterpret_cast<T const*>(&data);
778 }
779 else
780 {
781 throw bad_variant_access("in get<T>()");
782 }
783 }
784#endif
785
786 // get_unchecked<T>() - T stored as recursive_wrapper<T>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800787 template <typename T,
788 typename std::enable_if<
789 (detail::direct_type<recursive_wrapper<T>, Types...>::index !=
790 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500791 VARIANT_INLINE T& get_unchecked()
792 {
793 return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
794 }
795
796#ifdef HAS_EXCEPTIONS
797 // get<T>() - T stored as recursive_wrapper<T>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800798 template <typename T,
799 typename std::enable_if<
800 (detail::direct_type<recursive_wrapper<T>, Types...>::index !=
801 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500802 VARIANT_INLINE T& get()
803 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800804 if (type_index ==
805 detail::direct_type<recursive_wrapper<T>, Types...>::index)
Patrick Williamsceefb312016-09-11 21:12:42 -0500806 {
807 return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
808 }
809 else
810 {
811 throw bad_variant_access("in get<T>()");
812 }
813 }
814#endif
815
Andrew Geissler072da3e2018-01-18 07:21:42 -0800816 template <typename T,
817 typename std::enable_if<
818 (detail::direct_type<recursive_wrapper<T>, Types...>::index !=
819 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500820 VARIANT_INLINE T const& get_unchecked() const
821 {
822 return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get();
823 }
824
825#ifdef HAS_EXCEPTIONS
Andrew Geissler072da3e2018-01-18 07:21:42 -0800826 template <typename T,
827 typename std::enable_if<
828 (detail::direct_type<recursive_wrapper<T>, Types...>::index !=
829 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500830 VARIANT_INLINE T const& get() const
831 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800832 if (type_index ==
833 detail::direct_type<recursive_wrapper<T>, Types...>::index)
Patrick Williamsceefb312016-09-11 21:12:42 -0500834 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800835 return (*reinterpret_cast<recursive_wrapper<T> const*>(&data))
836 .get();
Patrick Williamsceefb312016-09-11 21:12:42 -0500837 }
838 else
839 {
840 throw bad_variant_access("in get<T>()");
841 }
842 }
843#endif
844
845 // get_unchecked<T>() - T stored as std::reference_wrapper<T>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800846 template <
847 typename T,
848 typename std::enable_if<
849 (detail::direct_type<std::reference_wrapper<T>, Types...>::index !=
850 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500851 VARIANT_INLINE T& get_unchecked()
852 {
853 return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
854 }
855
856#ifdef HAS_EXCEPTIONS
857 // get<T>() - T stored as std::reference_wrapper<T>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800858 template <
859 typename T,
860 typename std::enable_if<
861 (detail::direct_type<std::reference_wrapper<T>, Types...>::index !=
862 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500863 VARIANT_INLINE T& get()
864 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800865 if (type_index ==
866 detail::direct_type<std::reference_wrapper<T>, Types...>::index)
Patrick Williamsceefb312016-09-11 21:12:42 -0500867 {
868 return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
869 }
870 else
871 {
872 throw bad_variant_access("in get<T>()");
873 }
874 }
875#endif
876
Andrew Geissler072da3e2018-01-18 07:21:42 -0800877 template <typename T,
878 typename std::enable_if<
879 (detail::direct_type<std::reference_wrapper<T const>,
880 Types...>::index !=
881 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500882 VARIANT_INLINE T const& get_unchecked() const
883 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800884 return (*reinterpret_cast<std::reference_wrapper<T const> const*>(
885 &data))
886 .get();
Patrick Williamsceefb312016-09-11 21:12:42 -0500887 }
888
889#ifdef HAS_EXCEPTIONS
Andrew Geissler072da3e2018-01-18 07:21:42 -0800890 template <typename T,
891 typename std::enable_if<
892 (detail::direct_type<std::reference_wrapper<T const>,
893 Types...>::index !=
894 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500895 VARIANT_INLINE T const& get() const
896 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800897 if (type_index == detail::direct_type<std::reference_wrapper<T const>,
898 Types...>::index)
Patrick Williamsceefb312016-09-11 21:12:42 -0500899 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800900 return (*reinterpret_cast<std::reference_wrapper<T const> const*>(
901 &data))
902 .get();
Patrick Williamsceefb312016-09-11 21:12:42 -0500903 }
904 else
905 {
906 throw bad_variant_access("in get<T>()");
907 }
908 }
909#endif
910
911 // This function is deprecated because it returns an internal index field.
912 // Use which() instead.
913 MAPBOX_VARIANT_DEPRECATED VARIANT_INLINE std::size_t get_type_index() const
914 {
915 return type_index;
916 }
917
918 VARIANT_INLINE int which() const noexcept
919 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800920 return static_cast<int>(sizeof...(Types) - type_index - 1);
Patrick Williamsceefb312016-09-11 21:12:42 -0500921 }
922
923 template <typename T, typename std::enable_if<
Andrew Geissler072da3e2018-01-18 07:21:42 -0800924 (detail::direct_type<T, Types...>::index !=
925 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500926 VARIANT_INLINE static constexpr int which() noexcept
927 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800928 return static_cast<int>(sizeof...(Types) -
929 detail::direct_type<T, Types...>::index - 1);
Patrick Williamsceefb312016-09-11 21:12:42 -0500930 }
931
932 // visitor
933 // unary
Andrew Geissler072da3e2018-01-18 07:21:42 -0800934 template <typename F, typename V,
935 typename R =
936 typename detail::result_of_unary_visit<F, first_type>::type>
Patrick Williamsceefb312016-09-11 21:12:42 -0500937 auto VARIANT_INLINE static visit(V const& v, F&& f)
Andrew Geissler072da3e2018-01-18 07:21:42 -0800938 -> decltype(detail::dispatcher<F, V, R, Types...>::apply_const(
939 v, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -0500940 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800941 return detail::dispatcher<F, V, R, Types...>::apply_const(
942 v, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500943 }
944 // non-const
Andrew Geissler072da3e2018-01-18 07:21:42 -0800945 template <typename F, typename V,
946 typename R =
947 typename detail::result_of_unary_visit<F, first_type>::type>
948 auto VARIANT_INLINE static visit(V& v, F&& f) -> decltype(
949 detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -0500950 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800951 return detail::dispatcher<F, V, R, Types...>::apply(v,
952 std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500953 }
954
955 // binary
956 // const
Andrew Geissler072da3e2018-01-18 07:21:42 -0800957 template <typename F, typename V,
958 typename R =
959 typename detail::result_of_binary_visit<F, first_type>::type>
Patrick Williamsceefb312016-09-11 21:12:42 -0500960 auto VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F&& f)
Andrew Geissler072da3e2018-01-18 07:21:42 -0800961 -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply_const(
962 v0, v1, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -0500963 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800964 return detail::binary_dispatcher<F, V, R, Types...>::apply_const(
965 v0, v1, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500966 }
967 // non-const
Andrew Geissler072da3e2018-01-18 07:21:42 -0800968 template <typename F, typename V,
969 typename R =
970 typename detail::result_of_binary_visit<F, first_type>::type>
Patrick Williamsceefb312016-09-11 21:12:42 -0500971 auto VARIANT_INLINE static binary_visit(V& v0, V& v1, F&& f)
Andrew Geissler072da3e2018-01-18 07:21:42 -0800972 -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply(
973 v0, v1, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -0500974 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800975 return detail::binary_dispatcher<F, V, R, Types...>::apply(
976 v0, v1, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500977 }
978
979 ~variant() noexcept // no-throw destructor
980 {
981 helper_type::destroy(type_index, &data);
982 }
983
984 // comparison operators
985 // equality
986 VARIANT_INLINE bool operator==(variant const& rhs) const
987 {
988 assert(valid() && rhs.valid());
989 if (this->which() != rhs.which())
990 {
991 return false;
992 }
993 detail::comparer<variant, detail::equal_comp> visitor(*this);
994 return visit(rhs, visitor);
995 }
996
997 VARIANT_INLINE bool operator!=(variant const& rhs) const
998 {
999 return !(*this == rhs);
1000 }
1001
1002 // less than
1003 VARIANT_INLINE bool operator<(variant const& rhs) const
1004 {
1005 assert(valid() && rhs.valid());
1006 if (this->which() != rhs.which())
1007 {
1008 return this->which() < rhs.which();
1009 }
1010 detail::comparer<variant, detail::less_comp> visitor(*this);
1011 return visit(rhs, visitor);
1012 }
1013 VARIANT_INLINE bool operator>(variant const& rhs) const
1014 {
1015 return rhs < *this;
1016 }
1017 VARIANT_INLINE bool operator<=(variant const& rhs) const
1018 {
1019 return !(*this > rhs);
1020 }
1021 VARIANT_INLINE bool operator>=(variant const& rhs) const
1022 {
1023 return !(*this < rhs);
1024 }
1025};
1026
1027// unary visitor interface
1028// const
1029template <typename F, typename V>
Andrew Geissler072da3e2018-01-18 07:21:42 -08001030auto VARIANT_INLINE apply_visitor(F&& f, V const& v)
1031 -> decltype(V::visit(v, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -05001032{
1033 return V::visit(v, std::forward<F>(f));
1034}
1035
1036// non-const
1037template <typename F, typename V>
Andrew Geissler072da3e2018-01-18 07:21:42 -08001038auto VARIANT_INLINE apply_visitor(F&& f, V& v)
1039 -> decltype(V::visit(v, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -05001040{
1041 return V::visit(v, std::forward<F>(f));
1042}
1043
1044// binary visitor interface
1045// const
1046template <typename F, typename V>
Andrew Geissler072da3e2018-01-18 07:21:42 -08001047auto VARIANT_INLINE apply_visitor(F&& f, V const& v0, V const& v1)
1048 -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -05001049{
1050 return V::binary_visit(v0, v1, std::forward<F>(f));
1051}
1052
1053// non-const
1054template <typename F, typename V>
Andrew Geissler072da3e2018-01-18 07:21:42 -08001055auto VARIANT_INLINE apply_visitor(F&& f, V& v0, V& v1)
1056 -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -05001057{
1058 return V::binary_visit(v0, v1, std::forward<F>(f));
1059}
1060
Andrew Geissler072da3e2018-01-18 07:21:42 -08001061 // getter interface
Patrick Williamsceefb312016-09-11 21:12:42 -05001062
1063#ifdef HAS_EXCEPTIONS
1064template <typename ResultType, typename T>
Andrew Geissler072da3e2018-01-18 07:21:42 -08001065auto get(T& var) -> decltype(var.template get<ResultType>())
Patrick Williamsceefb312016-09-11 21:12:42 -05001066{
1067 return var.template get<ResultType>();
1068}
1069#endif
1070
Andrew Geissler072da3e2018-01-18 07:21:42 -08001071template <typename ResultType, typename T> ResultType& get_unchecked(T& var)
Patrick Williamsceefb312016-09-11 21:12:42 -05001072{
1073 return var.template get_unchecked<ResultType>();
1074}
1075
1076#ifdef HAS_EXCEPTIONS
1077template <typename ResultType, typename T>
Andrew Geissler072da3e2018-01-18 07:21:42 -08001078auto get(T const& var) -> decltype(var.template get<ResultType>())
Patrick Williamsceefb312016-09-11 21:12:42 -05001079{
1080 return var.template get<ResultType>();
1081}
1082#endif
1083
1084template <typename ResultType, typename T>
1085ResultType const& get_unchecked(T const& var)
1086{
1087 return var.template get_unchecked<ResultType>();
1088}
1089} // namespace util
1090} // namespace mapbox
1091
1092#endif // MAPBOX_UTIL_VARIANT_HPP