blob: 2019fc51eb921fa08a09731f929e59dcfc5f8877 [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>
Patrick Venture95269db2018-08-31 09:19:17 -07005#include <cstddef> // size_t
6#include <mapbox/recursive_wrapper.hpp>
Patrick Williamsceefb312016-09-11 21:12:42 -05007#include <new> // operator new
8#include <stdexcept> // runtime_error
9#include <string>
10#include <tuple>
11#include <type_traits>
12#include <typeinfo>
13#include <utility>
14
Patrick Williamsceefb312016-09-11 21:12:42 -050015// clang-format off
16// [[deprecated]] is only available in C++14, use this for the time being
17#if __cplusplus <= 201103L
18# ifdef __GNUC__
19# define MAPBOX_VARIANT_DEPRECATED __attribute__((deprecated))
20# elif defined(_MSC_VER)
21# define MAPBOX_VARIANT_DEPRECATED __declspec(deprecated)
22# else
23# define MAPBOX_VARIANT_DEPRECATED
24# endif
25#else
26# define MAPBOX_VARIANT_DEPRECATED [[deprecated]]
27#endif
28
29
30#ifdef _MSC_VER
31// https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx
32# ifdef NDEBUG
33# define VARIANT_INLINE __forceinline
34# else
35# define VARIANT_INLINE //__declspec(noinline)
36# endif
37#else
38# ifdef NDEBUG
39# define VARIANT_INLINE //inline __attribute__((always_inline))
40# else
41# define VARIANT_INLINE __attribute__((noinline))
42# endif
43#endif
44// clang-format on
45
46// Exceptions
Andrew Geissler072da3e2018-01-18 07:21:42 -080047#if defined(__EXCEPTIONS) || defined(_MSC_VER)
Patrick Williamsceefb312016-09-11 21:12:42 -050048#define HAS_EXCEPTIONS
49#endif
50
51#define VARIANT_MAJOR_VERSION 1
52#define VARIANT_MINOR_VERSION 1
53#define VARIANT_PATCH_VERSION 0
54
Andrew Geissler072da3e2018-01-18 07:21:42 -080055#define VARIANT_VERSION \
56 (VARIANT_MAJOR_VERSION * 100000) + (VARIANT_MINOR_VERSION * 100) + \
57 (VARIANT_PATCH_VERSION)
Patrick Williamsceefb312016-09-11 21:12:42 -050058
Andrew Geissler072da3e2018-01-18 07:21:42 -080059namespace mapbox
60{
61namespace util
62{
Patrick Williamsceefb312016-09-11 21:12:42 -050063
64// XXX This should derive from std::logic_error instead of std::runtime_error.
65// See https://github.com/mapbox/variant/issues/48 for details.
66class bad_variant_access : public std::runtime_error
67{
68
Andrew Geissler072da3e2018-01-18 07:21:42 -080069 public:
70 explicit bad_variant_access(const std::string& what_arg) :
71 runtime_error(what_arg)
72 {
73 }
Patrick Williamsceefb312016-09-11 21:12:42 -050074
Andrew Geissler072da3e2018-01-18 07:21:42 -080075 explicit bad_variant_access(const char* what_arg) : runtime_error(what_arg)
76 {
77 }
Patrick Williamsceefb312016-09-11 21:12:42 -050078
79}; // class bad_variant_access
80
Andrew Geissler072da3e2018-01-18 07:21:42 -080081template <typename R = void> struct MAPBOX_VARIANT_DEPRECATED static_visitor
Patrick Williamsceefb312016-09-11 21:12:42 -050082{
83 using result_type = R;
84
Andrew Geissler072da3e2018-01-18 07:21:42 -080085 protected:
86 static_visitor()
87 {
88 }
89 ~static_visitor()
90 {
91 }
Patrick Williamsceefb312016-09-11 21:12:42 -050092};
93
Andrew Geissler072da3e2018-01-18 07:21:42 -080094namespace detail
95{
Patrick Williamsceefb312016-09-11 21:12:42 -050096
97static constexpr std::size_t invalid_value = std::size_t(-1);
98
Andrew Geissler072da3e2018-01-18 07:21:42 -080099template <typename T, typename... Types> struct direct_type;
Patrick Williamsceefb312016-09-11 21:12:42 -0500100
101template <typename T, typename First, typename... Types>
102struct direct_type<T, First, Types...>
103{
104 static constexpr std::size_t index = std::is_same<T, First>::value
Andrew Geissler072da3e2018-01-18 07:21:42 -0800105 ? sizeof...(Types)
106 : direct_type<T, Types...>::index;
Patrick Williamsceefb312016-09-11 21:12:42 -0500107};
108
Andrew Geissler072da3e2018-01-18 07:21:42 -0800109template <typename T> struct direct_type<T>
Patrick Williamsceefb312016-09-11 21:12:42 -0500110{
111 static constexpr std::size_t index = invalid_value;
112};
113
114#if __cpp_lib_logical_traits >= 201510L
115
116using std::disjunction;
117
118#else
119
Andrew Geissler072da3e2018-01-18 07:21:42 -0800120template <typename...> struct disjunction : std::false_type
121{
122};
Patrick Williamsceefb312016-09-11 21:12:42 -0500123
Andrew Geissler072da3e2018-01-18 07:21:42 -0800124template <typename B1> struct disjunction<B1> : B1
125{
126};
Patrick Williamsceefb312016-09-11 21:12:42 -0500127
128template <typename B1, typename B2>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800129struct disjunction<B1, B2> : std::conditional<B1::value, B1, B2>::type
130{
131};
Patrick Williamsceefb312016-09-11 21:12:42 -0500132
133template <typename B1, typename... Bs>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800134struct disjunction<B1, Bs...>
135 : std::conditional<B1::value, B1, disjunction<Bs...>>::type
136{
137};
Patrick Williamsceefb312016-09-11 21:12:42 -0500138
139#endif
140
Andrew Geissler072da3e2018-01-18 07:21:42 -0800141template <typename T, typename... Types> struct convertible_type;
Patrick Williamsceefb312016-09-11 21:12:42 -0500142
143template <typename T, typename First, typename... Types>
144struct convertible_type<T, First, Types...>
145{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800146 static constexpr std::size_t index =
147 std::is_convertible<T, First>::value
148 ? disjunction<std::is_convertible<T, Types>...>::value
149 ? invalid_value
150 : sizeof...(Types)
151 : convertible_type<T, Types...>::index;
Patrick Williamsceefb312016-09-11 21:12:42 -0500152};
153
Andrew Geissler072da3e2018-01-18 07:21:42 -0800154template <typename T> struct convertible_type<T>
Patrick Williamsceefb312016-09-11 21:12:42 -0500155{
156 static constexpr std::size_t index = invalid_value;
157};
158
Andrew Geissler072da3e2018-01-18 07:21:42 -0800159template <typename T, typename... Types> struct value_traits
Patrick Williamsceefb312016-09-11 21:12:42 -0500160{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800161 using value_type = typename std::remove_const<
162 typename std::remove_reference<T>::type>::type;
163 static constexpr std::size_t direct_index =
164 direct_type<value_type, Types...>::index;
Patrick Williamsceefb312016-09-11 21:12:42 -0500165 static constexpr bool is_direct = direct_index != invalid_value;
Andrew Geissler072da3e2018-01-18 07:21:42 -0800166 static constexpr std::size_t index =
167 is_direct ? direct_index
168 : convertible_type<value_type, Types...>::index;
Patrick Williamsceefb312016-09-11 21:12:42 -0500169 static constexpr bool is_valid = index != invalid_value;
Andrew Geissler072da3e2018-01-18 07:21:42 -0800170 static constexpr std::size_t tindex =
171 is_valid ? sizeof...(Types) - index : 0;
172 using target_type =
173 typename std::tuple_element<tindex, std::tuple<void, Types...>>::type;
Patrick Williamsceefb312016-09-11 21:12:42 -0500174};
175
Andrew Geissler072da3e2018-01-18 07:21:42 -0800176template <typename T, typename R = void> struct enable_if_type
Patrick Williamsceefb312016-09-11 21:12:42 -0500177{
178 using type = R;
179};
180
181template <typename F, typename V, typename Enable = void>
182struct result_of_unary_visit
183{
184 using type = typename std::result_of<F(V&)>::type;
185};
186
187template <typename F, typename V>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800188struct result_of_unary_visit<
189 F, V, typename enable_if_type<typename F::result_type>::type>
Patrick Williamsceefb312016-09-11 21:12:42 -0500190{
191 using type = typename F::result_type;
192};
193
194template <typename F, typename V, typename Enable = void>
195struct result_of_binary_visit
196{
197 using type = typename std::result_of<F(V&, V&)>::type;
198};
199
200template <typename F, typename V>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800201struct result_of_binary_visit<
202 F, V, typename enable_if_type<typename F::result_type>::type>
Patrick Williamsceefb312016-09-11 21:12:42 -0500203{
204 using type = typename F::result_type;
205};
206
Andrew Geissler072da3e2018-01-18 07:21:42 -0800207template <std::size_t arg1, std::size_t... others> struct static_max;
Patrick Williamsceefb312016-09-11 21:12:42 -0500208
Andrew Geissler072da3e2018-01-18 07:21:42 -0800209template <std::size_t arg> struct static_max<arg>
Patrick Williamsceefb312016-09-11 21:12:42 -0500210{
211 static const std::size_t value = arg;
212};
213
214template <std::size_t arg1, std::size_t arg2, std::size_t... others>
215struct static_max<arg1, arg2, others...>
216{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800217 static const std::size_t value = arg1 >= arg2
218 ? static_max<arg1, others...>::value
219 : static_max<arg2, others...>::value;
Patrick Williamsceefb312016-09-11 21:12:42 -0500220};
221
Andrew Geissler072da3e2018-01-18 07:21:42 -0800222template <typename... Types> struct variant_helper;
Patrick Williamsceefb312016-09-11 21:12:42 -0500223
Andrew Geissler072da3e2018-01-18 07:21:42 -0800224template <typename T, typename... Types> struct variant_helper<T, Types...>
Patrick Williamsceefb312016-09-11 21:12:42 -0500225{
226 VARIANT_INLINE static void destroy(const std::size_t type_index, void* data)
227 {
228 if (type_index == sizeof...(Types))
229 {
230 reinterpret_cast<T*>(data)->~T();
231 }
232 else
233 {
234 variant_helper<Types...>::destroy(type_index, data);
235 }
236 }
237
Andrew Geissler072da3e2018-01-18 07:21:42 -0800238 VARIANT_INLINE static void move(const std::size_t old_type_index,
239 void* old_value, void* new_value)
Patrick Williamsceefb312016-09-11 21:12:42 -0500240 {
241 if (old_type_index == sizeof...(Types))
242 {
243 new (new_value) T(std::move(*reinterpret_cast<T*>(old_value)));
244 }
245 else
246 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800247 variant_helper<Types...>::move(old_type_index, old_value,
248 new_value);
Patrick Williamsceefb312016-09-11 21:12:42 -0500249 }
250 }
251
Andrew Geissler072da3e2018-01-18 07:21:42 -0800252 VARIANT_INLINE static void copy(const std::size_t old_type_index,
253 const void* old_value, void* new_value)
Patrick Williamsceefb312016-09-11 21:12:42 -0500254 {
255 if (old_type_index == sizeof...(Types))
256 {
257 new (new_value) T(*reinterpret_cast<const T*>(old_value));
258 }
259 else
260 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800261 variant_helper<Types...>::copy(old_type_index, old_value,
262 new_value);
Patrick Williamsceefb312016-09-11 21:12:42 -0500263 }
264 }
265};
266
Andrew Geissler072da3e2018-01-18 07:21:42 -0800267template <> struct variant_helper<>
Patrick Williamsceefb312016-09-11 21:12:42 -0500268{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800269 VARIANT_INLINE static void destroy(const std::size_t, void*)
270 {
271 }
272 VARIANT_INLINE static void move(const std::size_t, void*, void*)
273 {
274 }
275 VARIANT_INLINE static void copy(const std::size_t, const void*, void*)
276 {
277 }
Patrick Williamsceefb312016-09-11 21:12:42 -0500278};
279
Andrew Geissler072da3e2018-01-18 07:21:42 -0800280template <typename T> struct unwrapper
Patrick Williamsceefb312016-09-11 21:12:42 -0500281{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800282 static T const& apply_const(T const& obj)
283 {
284 return obj;
285 }
286 static T& apply(T& obj)
287 {
288 return obj;
289 }
Patrick Williamsceefb312016-09-11 21:12:42 -0500290};
291
Andrew Geissler072da3e2018-01-18 07:21:42 -0800292template <typename T> struct unwrapper<recursive_wrapper<T>>
Patrick Williamsceefb312016-09-11 21:12:42 -0500293{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800294 static auto apply_const(recursive_wrapper<T> const& obj) ->
295 typename recursive_wrapper<T>::type const&
Patrick Williamsceefb312016-09-11 21:12:42 -0500296 {
297 return obj.get();
298 }
Andrew Geissler072da3e2018-01-18 07:21:42 -0800299 static auto apply(recursive_wrapper<T>& obj) ->
300 typename recursive_wrapper<T>::type&
Patrick Williamsceefb312016-09-11 21:12:42 -0500301 {
302 return obj.get();
303 }
304};
305
Andrew Geissler072da3e2018-01-18 07:21:42 -0800306template <typename T> struct unwrapper<std::reference_wrapper<T>>
Patrick Williamsceefb312016-09-11 21:12:42 -0500307{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800308 static auto apply_const(std::reference_wrapper<T> const& obj) ->
309 typename std::reference_wrapper<T>::type const&
Patrick Williamsceefb312016-09-11 21:12:42 -0500310 {
311 return obj.get();
312 }
Andrew Geissler072da3e2018-01-18 07:21:42 -0800313 static auto apply(std::reference_wrapper<T>& obj) ->
314 typename std::reference_wrapper<T>::type&
Patrick Williamsceefb312016-09-11 21:12:42 -0500315 {
316 return obj.get();
317 }
318};
319
320template <typename F, typename V, typename R, typename... Types>
321struct dispatcher;
322
323template <typename F, typename V, typename R, typename T, typename... Types>
324struct dispatcher<F, V, R, T, Types...>
325{
326 VARIANT_INLINE static R apply_const(V const& v, F&& f)
327 {
328 if (v.template is<T>())
329 {
330 return f(unwrapper<T>::apply_const(v.template get_unchecked<T>()));
331 }
332 else
333 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800334 return dispatcher<F, V, R, Types...>::apply_const(
335 v, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500336 }
337 }
338
339 VARIANT_INLINE static R apply(V& v, F&& f)
340 {
341 if (v.template is<T>())
342 {
343 return f(unwrapper<T>::apply(v.template get_unchecked<T>()));
344 }
345 else
346 {
347 return dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
348 }
349 }
350};
351
352template <typename F, typename V, typename R, typename T>
353struct dispatcher<F, V, R, T>
354{
355 VARIANT_INLINE static R apply_const(V const& v, F&& f)
356 {
357 return f(unwrapper<T>::apply_const(v.template get_unchecked<T>()));
358 }
359
360 VARIANT_INLINE static R apply(V& v, F&& f)
361 {
362 return f(unwrapper<T>::apply(v.template get_unchecked<T>()));
363 }
364};
365
366template <typename F, typename V, typename R, typename T, typename... Types>
367struct binary_dispatcher_rhs;
368
Andrew Geissler072da3e2018-01-18 07:21:42 -0800369template <typename F, typename V, typename R, typename T0, typename T1,
370 typename... Types>
Patrick Williamsceefb312016-09-11 21:12:42 -0500371struct binary_dispatcher_rhs<F, V, R, T0, T1, Types...>
372{
373 VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
374 {
375 if (rhs.template is<T1>()) // call binary functor
376 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800377 return f(
378 unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()),
379 unwrapper<T1>::apply_const(rhs.template get_unchecked<T1>()));
Patrick Williamsceefb312016-09-11 21:12:42 -0500380 }
381 else
382 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800383 return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply_const(
384 lhs, rhs, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500385 }
386 }
387
388 VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
389 {
390 if (rhs.template is<T1>()) // call binary functor
391 {
392 return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()),
393 unwrapper<T1>::apply(rhs.template get_unchecked<T1>()));
394 }
395 else
396 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800397 return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply(
398 lhs, rhs, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500399 }
400 }
401};
402
403template <typename F, typename V, typename R, typename T0, typename T1>
404struct binary_dispatcher_rhs<F, V, R, T0, T1>
405{
406 VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
407 {
408 return f(unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()),
409 unwrapper<T1>::apply_const(rhs.template get_unchecked<T1>()));
410 }
411
412 VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
413 {
414 return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()),
415 unwrapper<T1>::apply(rhs.template get_unchecked<T1>()));
416 }
417};
418
419template <typename F, typename V, typename R, typename T, typename... Types>
420struct binary_dispatcher_lhs;
421
Andrew Geissler072da3e2018-01-18 07:21:42 -0800422template <typename F, typename V, typename R, typename T0, typename T1,
423 typename... Types>
Patrick Williamsceefb312016-09-11 21:12:42 -0500424struct binary_dispatcher_lhs<F, V, R, T0, T1, Types...>
425{
426 VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
427 {
428 if (lhs.template is<T1>()) // call binary functor
429 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800430 return f(
431 unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()),
432 unwrapper<T0>::apply_const(rhs.template get_unchecked<T0>()));
Patrick Williamsceefb312016-09-11 21:12:42 -0500433 }
434 else
435 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800436 return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply_const(
437 lhs, rhs, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500438 }
439 }
440
441 VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
442 {
443 if (lhs.template is<T1>()) // call binary functor
444 {
445 return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()),
446 unwrapper<T0>::apply(rhs.template get_unchecked<T0>()));
447 }
448 else
449 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800450 return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply(
451 lhs, rhs, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500452 }
453 }
454};
455
456template <typename F, typename V, typename R, typename T0, typename T1>
457struct binary_dispatcher_lhs<F, V, R, T0, T1>
458{
459 VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
460 {
461 return f(unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()),
462 unwrapper<T0>::apply_const(rhs.template get_unchecked<T0>()));
463 }
464
465 VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
466 {
467 return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()),
468 unwrapper<T0>::apply(rhs.template get_unchecked<T0>()));
469 }
470};
471
472template <typename F, typename V, typename R, typename... Types>
473struct binary_dispatcher;
474
475template <typename F, typename V, typename R, typename T, typename... Types>
476struct binary_dispatcher<F, V, R, T, Types...>
477{
478 VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
479 {
480 if (v0.template is<T>())
481 {
482 if (v1.template is<T>())
483 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800484 return f(
485 unwrapper<T>::apply_const(v0.template get_unchecked<T>()),
486 unwrapper<T>::apply_const(
487 v1.template get_unchecked<T>())); // call binary functor
Patrick Williamsceefb312016-09-11 21:12:42 -0500488 }
489 else
490 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800491 return binary_dispatcher_rhs<F, V, R, T, Types...>::apply_const(
492 v0, v1, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500493 }
494 }
495 else if (v1.template is<T>())
496 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800497 return binary_dispatcher_lhs<F, V, R, T, Types...>::apply_const(
498 v0, v1, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500499 }
Andrew Geissler072da3e2018-01-18 07:21:42 -0800500 return binary_dispatcher<F, V, R, Types...>::apply_const(
501 v0, v1, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500502 }
503
504 VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
505 {
506 if (v0.template is<T>())
507 {
508 if (v1.template is<T>())
509 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800510 return f(
511 unwrapper<T>::apply(v0.template get_unchecked<T>()),
512 unwrapper<T>::apply(
513 v1.template get_unchecked<T>())); // call binary functor
Patrick Williamsceefb312016-09-11 21:12:42 -0500514 }
515 else
516 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800517 return binary_dispatcher_rhs<F, V, R, T, Types...>::apply(
518 v0, v1, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500519 }
520 }
521 else if (v1.template is<T>())
522 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800523 return binary_dispatcher_lhs<F, V, R, T, Types...>::apply(
524 v0, v1, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500525 }
Andrew Geissler072da3e2018-01-18 07:21:42 -0800526 return binary_dispatcher<F, V, R, Types...>::apply(v0, v1,
527 std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500528 }
529};
530
531template <typename F, typename V, typename R, typename T>
532struct binary_dispatcher<F, V, R, T>
533{
534 VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
535 {
536 return f(unwrapper<T>::apply_const(v0.template get_unchecked<T>()),
Andrew Geissler072da3e2018-01-18 07:21:42 -0800537 unwrapper<T>::apply_const(
538 v1.template get_unchecked<T>())); // call binary functor
Patrick Williamsceefb312016-09-11 21:12:42 -0500539 }
540
541 VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
542 {
543 return f(unwrapper<T>::apply(v0.template get_unchecked<T>()),
Andrew Geissler072da3e2018-01-18 07:21:42 -0800544 unwrapper<T>::apply(
545 v1.template get_unchecked<T>())); // call binary functor
Patrick Williamsceefb312016-09-11 21:12:42 -0500546 }
547};
548
549// comparator functors
550struct equal_comp
551{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800552 template <typename T> bool operator()(T const& lhs, T const& rhs) const
Patrick Williamsceefb312016-09-11 21:12:42 -0500553 {
554 return lhs == rhs;
555 }
556};
557
558struct less_comp
559{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800560 template <typename T> bool operator()(T const& lhs, T const& rhs) const
Patrick Williamsceefb312016-09-11 21:12:42 -0500561 {
562 return lhs < rhs;
563 }
564};
565
Andrew Geissler072da3e2018-01-18 07:21:42 -0800566template <typename Variant, typename Comp> class comparer
Patrick Williamsceefb312016-09-11 21:12:42 -0500567{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800568 public:
569 explicit comparer(Variant const& lhs) noexcept : lhs_(lhs)
570 {
571 }
Patrick Williamsceefb312016-09-11 21:12:42 -0500572 comparer& operator=(comparer const&) = delete;
573 // visitor
Andrew Geissler072da3e2018-01-18 07:21:42 -0800574 template <typename T> bool operator()(T const& rhs_content) const
Patrick Williamsceefb312016-09-11 21:12:42 -0500575 {
576 T const& lhs_content = lhs_.template get_unchecked<T>();
577 return Comp()(lhs_content, rhs_content);
578 }
579
Andrew Geissler072da3e2018-01-18 07:21:42 -0800580 private:
Patrick Williamsceefb312016-09-11 21:12:42 -0500581 Variant const& lhs_;
582};
583
584} // namespace detail
585
586struct no_init
587{
588};
589
Andrew Geissler072da3e2018-01-18 07:21:42 -0800590template <typename... Types> class variant
Patrick Williamsceefb312016-09-11 21:12:42 -0500591{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800592 static_assert(sizeof...(Types) > 0,
593 "Template parameter type list of variant can not be empty");
594 static_assert(!detail::disjunction<std::is_reference<Types>...>::value,
595 "Variant can not hold reference types. Maybe use "
596 "std::reference_wrapper?");
Patrick Williamsceefb312016-09-11 21:12:42 -0500597
Andrew Geissler072da3e2018-01-18 07:21:42 -0800598 private:
599 static const std::size_t data_size =
600 detail::static_max<sizeof(Types)...>::value;
601 static const std::size_t data_align =
602 detail::static_max<alignof(Types)...>::value;
Patrick Williamsceefb312016-09-11 21:12:42 -0500603
Andrew Geissler072da3e2018-01-18 07:21:42 -0800604 using first_type =
605 typename std::tuple_element<0, std::tuple<Types...>>::type;
606 using data_type =
607 typename std::aligned_storage<data_size, data_align>::type;
Patrick Williamsceefb312016-09-11 21:12:42 -0500608 using helper_type = detail::variant_helper<Types...>;
609
610 std::size_t type_index;
611 data_type data;
612
Andrew Geissler072da3e2018-01-18 07:21:42 -0800613 public:
614 VARIANT_INLINE variant() noexcept(
615 std::is_nothrow_default_constructible<first_type>::value) :
616 type_index(sizeof...(Types) - 1)
Patrick Williamsceefb312016-09-11 21:12:42 -0500617 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800618 static_assert(std::is_default_constructible<first_type>::value,
619 "First type in variant must be default constructible to "
620 "allow default construction of variant");
Patrick Williamsceefb312016-09-11 21:12:42 -0500621 new (&data) first_type();
622 }
623
Andrew Geissler072da3e2018-01-18 07:21:42 -0800624 VARIANT_INLINE variant(no_init) noexcept : type_index(detail::invalid_value)
625 {
626 }
Patrick Williamsceefb312016-09-11 21:12:42 -0500627
628 // http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
629 template <typename T, typename Traits = detail::value_traits<T, Types...>,
630 typename Enable = typename std::enable_if<Traits::is_valid>::type>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800631 VARIANT_INLINE variant(T&& val) noexcept(
632 std::is_nothrow_constructible<typename Traits::target_type,
633 T&&>::value) :
634 type_index(Traits::index)
Patrick Williamsceefb312016-09-11 21:12:42 -0500635 {
636 new (&data) typename Traits::target_type(std::forward<T>(val));
637 }
638
Andrew Geissler072da3e2018-01-18 07:21:42 -0800639 VARIANT_INLINE variant(variant<Types...> const& old) :
640 type_index(old.type_index)
Patrick Williamsceefb312016-09-11 21:12:42 -0500641 {
642 helper_type::copy(old.type_index, &old.data, &data);
643 }
644
Andrew Geissler072da3e2018-01-18 07:21:42 -0800645 VARIANT_INLINE variant(variant<Types...>&& old) noexcept(
646 std::is_nothrow_move_constructible<std::tuple<Types...>>::value) :
647 type_index(old.type_index)
Patrick Williamsceefb312016-09-11 21:12:42 -0500648 {
649 helper_type::move(old.type_index, &old.data, &data);
650 }
651
Andrew Geissler072da3e2018-01-18 07:21:42 -0800652 private:
Patrick Williamsceefb312016-09-11 21:12:42 -0500653 VARIANT_INLINE void copy_assign(variant<Types...> const& rhs)
654 {
655 helper_type::destroy(type_index, &data);
656 type_index = detail::invalid_value;
657 helper_type::copy(rhs.type_index, &rhs.data, &data);
658 type_index = rhs.type_index;
659 }
660
661 VARIANT_INLINE void move_assign(variant<Types...>&& rhs)
662 {
663 helper_type::destroy(type_index, &data);
664 type_index = detail::invalid_value;
665 helper_type::move(rhs.type_index, &rhs.data, &data);
666 type_index = rhs.type_index;
667 }
668
Andrew Geissler072da3e2018-01-18 07:21:42 -0800669 public:
Patrick Williamsceefb312016-09-11 21:12:42 -0500670 VARIANT_INLINE variant<Types...>& operator=(variant<Types...>&& other)
671 {
672 move_assign(std::move(other));
673 return *this;
674 }
675
676 VARIANT_INLINE variant<Types...>& operator=(variant<Types...> const& other)
677 {
678 copy_assign(other);
679 return *this;
680 }
681
682 // conversions
683 // move-assign
684 template <typename T>
685 VARIANT_INLINE variant<Types...>& operator=(T&& rhs) noexcept
686 {
687 variant<Types...> temp(std::forward<T>(rhs));
688 move_assign(std::move(temp));
689 return *this;
690 }
691
692 // copy-assign
693 template <typename T>
694 VARIANT_INLINE variant<Types...>& operator=(T const& rhs)
695 {
696 variant<Types...> temp(rhs);
697 copy_assign(temp);
698 return *this;
699 }
700
701 template <typename T, typename std::enable_if<
Andrew Geissler072da3e2018-01-18 07:21:42 -0800702 (detail::direct_type<T, Types...>::index !=
703 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500704 VARIANT_INLINE bool is() const
705 {
706 return type_index == detail::direct_type<T, Types...>::index;
707 }
708
Andrew Geissler072da3e2018-01-18 07:21:42 -0800709 template <typename T,
710 typename std::enable_if<
711 (detail::direct_type<recursive_wrapper<T>, Types...>::index !=
712 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500713 VARIANT_INLINE bool is() const
714 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800715 return type_index ==
716 detail::direct_type<recursive_wrapper<T>, Types...>::index;
Patrick Williamsceefb312016-09-11 21:12:42 -0500717 }
718
719 VARIANT_INLINE bool valid() const
720 {
721 return type_index != detail::invalid_value;
722 }
723
724 template <typename T, typename... Args>
725 VARIANT_INLINE void set(Args&&... args)
726 {
727 helper_type::destroy(type_index, &data);
728 type_index = detail::invalid_value;
729 new (&data) T(std::forward<Args>(args)...);
730 type_index = detail::direct_type<T, Types...>::index;
731 }
732
733 // get_unchecked<T>()
734 template <typename T, typename std::enable_if<
Andrew Geissler072da3e2018-01-18 07:21:42 -0800735 (detail::direct_type<T, Types...>::index !=
736 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500737 VARIANT_INLINE T& get_unchecked()
738 {
739 return *reinterpret_cast<T*>(&data);
740 }
741
742#ifdef HAS_EXCEPTIONS
743 // get<T>()
744 template <typename T, typename std::enable_if<
Andrew Geissler072da3e2018-01-18 07:21:42 -0800745 (detail::direct_type<T, Types...>::index !=
746 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500747 VARIANT_INLINE T& get()
748 {
749 if (type_index == detail::direct_type<T, Types...>::index)
750 {
751 return *reinterpret_cast<T*>(&data);
752 }
753 else
754 {
755 throw bad_variant_access("in get<T>()");
756 }
757 }
758#endif
759
760 template <typename T, typename std::enable_if<
Andrew Geissler072da3e2018-01-18 07:21:42 -0800761 (detail::direct_type<T, Types...>::index !=
762 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500763 VARIANT_INLINE T const& get_unchecked() const
764 {
765 return *reinterpret_cast<T const*>(&data);
766 }
767
768#ifdef HAS_EXCEPTIONS
769 template <typename T, typename std::enable_if<
Andrew Geissler072da3e2018-01-18 07:21:42 -0800770 (detail::direct_type<T, Types...>::index !=
771 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500772 VARIANT_INLINE T const& get() const
773 {
774 if (type_index == detail::direct_type<T, Types...>::index)
775 {
776 return *reinterpret_cast<T const*>(&data);
777 }
778 else
779 {
780 throw bad_variant_access("in get<T>()");
781 }
782 }
783#endif
784
785 // get_unchecked<T>() - T stored as recursive_wrapper<T>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800786 template <typename T,
787 typename std::enable_if<
788 (detail::direct_type<recursive_wrapper<T>, Types...>::index !=
789 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500790 VARIANT_INLINE T& get_unchecked()
791 {
792 return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
793 }
794
795#ifdef HAS_EXCEPTIONS
796 // get<T>() - T stored as recursive_wrapper<T>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800797 template <typename T,
798 typename std::enable_if<
799 (detail::direct_type<recursive_wrapper<T>, Types...>::index !=
800 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500801 VARIANT_INLINE T& get()
802 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800803 if (type_index ==
804 detail::direct_type<recursive_wrapper<T>, Types...>::index)
Patrick Williamsceefb312016-09-11 21:12:42 -0500805 {
806 return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
807 }
808 else
809 {
810 throw bad_variant_access("in get<T>()");
811 }
812 }
813#endif
814
Andrew Geissler072da3e2018-01-18 07:21:42 -0800815 template <typename T,
816 typename std::enable_if<
817 (detail::direct_type<recursive_wrapper<T>, Types...>::index !=
818 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500819 VARIANT_INLINE T const& get_unchecked() const
820 {
821 return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get();
822 }
823
824#ifdef HAS_EXCEPTIONS
Andrew Geissler072da3e2018-01-18 07:21:42 -0800825 template <typename T,
826 typename std::enable_if<
827 (detail::direct_type<recursive_wrapper<T>, Types...>::index !=
828 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500829 VARIANT_INLINE T const& get() const
830 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800831 if (type_index ==
832 detail::direct_type<recursive_wrapper<T>, Types...>::index)
Patrick Williamsceefb312016-09-11 21:12:42 -0500833 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800834 return (*reinterpret_cast<recursive_wrapper<T> const*>(&data))
835 .get();
Patrick Williamsceefb312016-09-11 21:12:42 -0500836 }
837 else
838 {
839 throw bad_variant_access("in get<T>()");
840 }
841 }
842#endif
843
844 // get_unchecked<T>() - T stored as std::reference_wrapper<T>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800845 template <
846 typename T,
847 typename std::enable_if<
848 (detail::direct_type<std::reference_wrapper<T>, Types...>::index !=
849 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500850 VARIANT_INLINE T& get_unchecked()
851 {
852 return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
853 }
854
855#ifdef HAS_EXCEPTIONS
856 // get<T>() - T stored as std::reference_wrapper<T>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800857 template <
858 typename T,
859 typename std::enable_if<
860 (detail::direct_type<std::reference_wrapper<T>, Types...>::index !=
861 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500862 VARIANT_INLINE T& get()
863 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800864 if (type_index ==
865 detail::direct_type<std::reference_wrapper<T>, Types...>::index)
Patrick Williamsceefb312016-09-11 21:12:42 -0500866 {
867 return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
868 }
869 else
870 {
871 throw bad_variant_access("in get<T>()");
872 }
873 }
874#endif
875
Andrew Geissler072da3e2018-01-18 07:21:42 -0800876 template <typename T,
877 typename std::enable_if<
878 (detail::direct_type<std::reference_wrapper<T const>,
879 Types...>::index !=
880 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500881 VARIANT_INLINE T const& get_unchecked() const
882 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800883 return (*reinterpret_cast<std::reference_wrapper<T const> const*>(
884 &data))
885 .get();
Patrick Williamsceefb312016-09-11 21:12:42 -0500886 }
887
888#ifdef HAS_EXCEPTIONS
Andrew Geissler072da3e2018-01-18 07:21:42 -0800889 template <typename T,
890 typename std::enable_if<
891 (detail::direct_type<std::reference_wrapper<T const>,
892 Types...>::index !=
893 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500894 VARIANT_INLINE T const& get() const
895 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800896 if (type_index == detail::direct_type<std::reference_wrapper<T const>,
897 Types...>::index)
Patrick Williamsceefb312016-09-11 21:12:42 -0500898 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800899 return (*reinterpret_cast<std::reference_wrapper<T const> const*>(
900 &data))
901 .get();
Patrick Williamsceefb312016-09-11 21:12:42 -0500902 }
903 else
904 {
905 throw bad_variant_access("in get<T>()");
906 }
907 }
908#endif
909
910 // This function is deprecated because it returns an internal index field.
911 // Use which() instead.
912 MAPBOX_VARIANT_DEPRECATED VARIANT_INLINE std::size_t get_type_index() const
913 {
914 return type_index;
915 }
916
917 VARIANT_INLINE int which() const noexcept
918 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800919 return static_cast<int>(sizeof...(Types) - type_index - 1);
Patrick Williamsceefb312016-09-11 21:12:42 -0500920 }
921
922 template <typename T, typename std::enable_if<
Andrew Geissler072da3e2018-01-18 07:21:42 -0800923 (detail::direct_type<T, Types...>::index !=
924 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500925 VARIANT_INLINE static constexpr int which() noexcept
926 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800927 return static_cast<int>(sizeof...(Types) -
928 detail::direct_type<T, Types...>::index - 1);
Patrick Williamsceefb312016-09-11 21:12:42 -0500929 }
930
931 // visitor
932 // unary
Andrew Geissler072da3e2018-01-18 07:21:42 -0800933 template <typename F, typename V,
934 typename R =
935 typename detail::result_of_unary_visit<F, first_type>::type>
Patrick Williamsceefb312016-09-11 21:12:42 -0500936 auto VARIANT_INLINE static visit(V const& v, F&& f)
Andrew Geissler072da3e2018-01-18 07:21:42 -0800937 -> decltype(detail::dispatcher<F, V, R, Types...>::apply_const(
938 v, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -0500939 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800940 return detail::dispatcher<F, V, R, Types...>::apply_const(
941 v, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500942 }
943 // non-const
Andrew Geissler072da3e2018-01-18 07:21:42 -0800944 template <typename F, typename V,
945 typename R =
946 typename detail::result_of_unary_visit<F, first_type>::type>
947 auto VARIANT_INLINE static visit(V& v, F&& f) -> decltype(
948 detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -0500949 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800950 return detail::dispatcher<F, V, R, Types...>::apply(v,
951 std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500952 }
953
954 // binary
955 // const
Andrew Geissler072da3e2018-01-18 07:21:42 -0800956 template <typename F, typename V,
957 typename R =
958 typename detail::result_of_binary_visit<F, first_type>::type>
Patrick Williamsceefb312016-09-11 21:12:42 -0500959 auto VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F&& f)
Andrew Geissler072da3e2018-01-18 07:21:42 -0800960 -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply_const(
961 v0, v1, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -0500962 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800963 return detail::binary_dispatcher<F, V, R, Types...>::apply_const(
964 v0, v1, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500965 }
966 // non-const
Andrew Geissler072da3e2018-01-18 07:21:42 -0800967 template <typename F, typename V,
968 typename R =
969 typename detail::result_of_binary_visit<F, first_type>::type>
Patrick Williamsceefb312016-09-11 21:12:42 -0500970 auto VARIANT_INLINE static binary_visit(V& v0, V& v1, F&& f)
Andrew Geissler072da3e2018-01-18 07:21:42 -0800971 -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply(
972 v0, v1, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -0500973 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800974 return detail::binary_dispatcher<F, V, R, Types...>::apply(
975 v0, v1, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500976 }
977
978 ~variant() noexcept // no-throw destructor
979 {
980 helper_type::destroy(type_index, &data);
981 }
982
983 // comparison operators
984 // equality
985 VARIANT_INLINE bool operator==(variant const& rhs) const
986 {
987 assert(valid() && rhs.valid());
988 if (this->which() != rhs.which())
989 {
990 return false;
991 }
992 detail::comparer<variant, detail::equal_comp> visitor(*this);
993 return visit(rhs, visitor);
994 }
995
996 VARIANT_INLINE bool operator!=(variant const& rhs) const
997 {
998 return !(*this == rhs);
999 }
1000
1001 // less than
1002 VARIANT_INLINE bool operator<(variant const& rhs) const
1003 {
1004 assert(valid() && rhs.valid());
1005 if (this->which() != rhs.which())
1006 {
1007 return this->which() < rhs.which();
1008 }
1009 detail::comparer<variant, detail::less_comp> visitor(*this);
1010 return visit(rhs, visitor);
1011 }
1012 VARIANT_INLINE bool operator>(variant const& rhs) const
1013 {
1014 return rhs < *this;
1015 }
1016 VARIANT_INLINE bool operator<=(variant const& rhs) const
1017 {
1018 return !(*this > rhs);
1019 }
1020 VARIANT_INLINE bool operator>=(variant const& rhs) const
1021 {
1022 return !(*this < rhs);
1023 }
1024};
1025
1026// unary visitor interface
1027// const
1028template <typename F, typename V>
Andrew Geissler072da3e2018-01-18 07:21:42 -08001029auto VARIANT_INLINE apply_visitor(F&& f, V const& v)
1030 -> decltype(V::visit(v, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -05001031{
1032 return V::visit(v, std::forward<F>(f));
1033}
1034
1035// non-const
1036template <typename F, typename V>
Andrew Geissler072da3e2018-01-18 07:21:42 -08001037auto VARIANT_INLINE apply_visitor(F&& f, V& v)
1038 -> decltype(V::visit(v, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -05001039{
1040 return V::visit(v, std::forward<F>(f));
1041}
1042
1043// binary visitor interface
1044// const
1045template <typename F, typename V>
Andrew Geissler072da3e2018-01-18 07:21:42 -08001046auto VARIANT_INLINE apply_visitor(F&& f, V const& v0, V const& v1)
1047 -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -05001048{
1049 return V::binary_visit(v0, v1, std::forward<F>(f));
1050}
1051
1052// non-const
1053template <typename F, typename V>
Andrew Geissler072da3e2018-01-18 07:21:42 -08001054auto VARIANT_INLINE apply_visitor(F&& f, V& v0, V& v1)
1055 -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -05001056{
1057 return V::binary_visit(v0, v1, std::forward<F>(f));
1058}
1059
Patrick Venture0b5d1e02018-08-31 09:12:15 -07001060// getter interface
Patrick Williamsceefb312016-09-11 21:12:42 -05001061
1062#ifdef HAS_EXCEPTIONS
1063template <typename ResultType, typename T>
Andrew Geissler072da3e2018-01-18 07:21:42 -08001064auto get(T& var) -> decltype(var.template get<ResultType>())
Patrick Williamsceefb312016-09-11 21:12:42 -05001065{
1066 return var.template get<ResultType>();
1067}
1068#endif
1069
Andrew Geissler072da3e2018-01-18 07:21:42 -08001070template <typename ResultType, typename T> ResultType& get_unchecked(T& var)
Patrick Williamsceefb312016-09-11 21:12:42 -05001071{
1072 return var.template get_unchecked<ResultType>();
1073}
1074
1075#ifdef HAS_EXCEPTIONS
1076template <typename ResultType, typename T>
Andrew Geissler072da3e2018-01-18 07:21:42 -08001077auto get(T const& var) -> decltype(var.template get<ResultType>())
Patrick Williamsceefb312016-09-11 21:12:42 -05001078{
1079 return var.template get<ResultType>();
1080}
1081#endif
1082
1083template <typename ResultType, typename T>
1084ResultType const& get_unchecked(T const& var)
1085{
1086 return var.template get_unchecked<ResultType>();
1087}
1088} // namespace util
1089} // namespace mapbox
1090
1091#endif // MAPBOX_UTIL_VARIANT_HPP