1 #ifndef OPENTRACING_UTIL_VARIANT_HPP
2 #define OPENTRACING_UTIL_VARIANT_HPP
5 #include <cstddef> // size_t
6 #include <new> // operator new
7 #include <stdexcept> // runtime_error
10 #include <type_traits>
13 #include <opentracing/version.h>
15 #include "recursive_wrapper.hpp"
18 // [[deprecated]] is only available in C++14, use this for the time being
19 #if __cplusplus <= 201103L
21 # define OPENTRACING_VARIANT_DEPRECATED __attribute__((deprecated))
22 # elif defined(_MSC_VER)
23 # define OPENTRACING_VARIANT_DEPRECATED __declspec(deprecated)
25 # define OPENTRACING_VARIANT_DEPRECATED
28 # define OPENTRACING_VARIANT_DEPRECATED [[deprecated]]
33 // https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx
35 #define VARIANT_INLINE __forceinline
37 #define VARIANT_INLINE __declspec(noinline)
41 #define VARIANT_INLINE inline __attribute__((always_inline))
43 #define VARIANT_INLINE __attribute__((noinline))
48 #define VARIANT_MAJOR_VERSION 1
49 #define VARIANT_MINOR_VERSION 1
50 #define VARIANT_PATCH_VERSION 0
52 #define VARIANT_VERSION (VARIANT_MAJOR_VERSION * 100000) + (VARIANT_MINOR_VERSION * 100) + (VARIANT_PATCH_VERSION)
54 namespace opentracing {
55 BEGIN_OPENTRACING_ABI_NAMESPACE
58 // XXX This should derive from std::logic_error instead of std::runtime_error.
59 // See https://github.com/opentracing/variant/issues/48 for details.
60 class bad_variant_access : public std::runtime_error
64 explicit bad_variant_access(const std::string& what_arg)
65 : runtime_error(what_arg) {}
67 explicit bad_variant_access(const char* what_arg)
68 : runtime_error(what_arg) {}
70 }; // class bad_variant_access
72 template <typename R = void>
73 struct OPENTRACING_VARIANT_DEPRECATED static_visitor
75 using result_type = R;
84 static constexpr std::size_t invalid_value = std::size_t(-1);
86 template <typename T, typename... Types>
89 template <typename T, typename First, typename... Types>
90 struct direct_type<T, First, Types...>
92 static constexpr std::size_t index = std::is_same<T, First>::value
94 : direct_type<T, Types...>::index;
100 static constexpr std::size_t index = invalid_value;
103 template <typename T, typename... Types>
104 struct convertible_type;
106 template <typename T, typename First, typename... Types>
107 struct convertible_type<T, First, Types...>
109 static constexpr std::size_t index = std::is_convertible<T, First>::value
111 : convertible_type<T, Types...>::index;
114 template <typename T>
115 struct convertible_type<T>
117 static constexpr std::size_t index = invalid_value;
120 template <typename T, typename... Types>
123 using value_type = typename std::remove_reference<T>::type;
124 static constexpr std::size_t direct_index = direct_type<value_type, Types...>::index;
125 static constexpr bool is_direct = direct_index != invalid_value;
126 static constexpr std::size_t index = is_direct ? direct_index : convertible_type<value_type, Types...>::index;
127 static constexpr bool is_valid = index != invalid_value;
128 static constexpr std::size_t tindex = is_valid ? sizeof...(Types)-index : 0;
129 using target_type = typename std::tuple_element<tindex, std::tuple<void, Types...>>::type;
132 // check if T is in Types...
133 template <typename T, typename... Types>
136 template <typename T, typename First, typename... Types>
137 struct has_type<T, First, Types...>
139 static constexpr bool value = std::is_same<T, First>::value || has_type<T, Types...>::value;
142 template <typename T>
143 struct has_type<T> : std::false_type
147 template <typename T, typename... Types>
148 struct is_valid_type;
150 template <typename T, typename First, typename... Types>
151 struct is_valid_type<T, First, Types...>
153 static constexpr bool value = std::is_convertible<T, First>::value || is_valid_type<T, Types...>::value;
156 template <typename T>
157 struct is_valid_type<T> : std::false_type
161 template <typename T, typename R = void>
162 struct enable_if_type
167 template <typename F, typename V, typename Enable = void>
168 struct result_of_unary_visit
170 using type = typename std::result_of<F(V&)>::type;
173 template <typename F, typename V>
174 struct result_of_unary_visit<F, V, typename enable_if_type<typename F::result_type>::type>
176 using type = typename F::result_type;
179 template <typename F, typename V, typename Enable = void>
180 struct result_of_binary_visit
182 using type = typename std::result_of<F(V&, V&)>::type;
185 template <typename F, typename V>
186 struct result_of_binary_visit<F, V, typename enable_if_type<typename F::result_type>::type>
188 using type = typename F::result_type;
191 template <std::size_t arg1, std::size_t... others>
194 template <std::size_t arg>
195 struct static_max<arg>
197 static const std::size_t value = arg;
200 template <std::size_t arg1, std::size_t arg2, std::size_t... others>
201 struct static_max<arg1, arg2, others...>
203 static const std::size_t value = arg1 >= arg2 ? static_max<arg1, others...>::value : static_max<arg2, others...>::value;
206 template <typename... Types>
207 struct variant_helper;
209 template <typename T, typename... Types>
210 struct variant_helper<T, Types...>
212 VARIANT_INLINE static void destroy(const std::size_t type_index, void* data)
214 if (type_index == sizeof...(Types))
216 reinterpret_cast<T*>(data)->~T();
220 variant_helper<Types...>::destroy(type_index, data);
224 VARIANT_INLINE static void move(const std::size_t old_type_index, void* old_value, void* new_value)
226 if (old_type_index == sizeof...(Types))
228 new (new_value) T(std::move(*reinterpret_cast<T*>(old_value)));
232 variant_helper<Types...>::move(old_type_index, old_value, new_value);
236 VARIANT_INLINE static void copy(const std::size_t old_type_index, const void* old_value, void* new_value)
238 if (old_type_index == sizeof...(Types))
240 new (new_value) T(*reinterpret_cast<const T*>(old_value));
244 variant_helper<Types...>::copy(old_type_index, old_value, new_value);
250 struct variant_helper<>
252 VARIANT_INLINE static void destroy(const std::size_t, void*) {}
253 VARIANT_INLINE static void move(const std::size_t, void*, void*) {}
254 VARIANT_INLINE static void copy(const std::size_t, const void*, void*) {}
257 template <typename T>
260 static T const& apply_const(T const& obj) { return obj; }
261 static T& apply(T& obj) { return obj; }
264 template <typename T>
265 struct unwrapper<recursive_wrapper<T>>
267 static auto apply_const(recursive_wrapper<T> const& obj)
268 -> typename recursive_wrapper<T>::type const&
272 static auto apply(recursive_wrapper<T>& obj)
273 -> typename recursive_wrapper<T>::type&
279 template <typename T>
280 struct unwrapper<std::reference_wrapper<T>>
282 static auto apply_const(std::reference_wrapper<T> const& obj)
283 -> typename std::reference_wrapper<T>::type const&
287 static auto apply(std::reference_wrapper<T>& obj)
288 -> typename std::reference_wrapper<T>::type&
294 template <typename F, typename V, typename R, typename... Types>
297 template <typename F, typename V, typename R, typename T, typename... Types>
298 struct dispatcher<F, V, R, T, Types...>
300 VARIANT_INLINE static R apply_const(V const& v, F&& f)
302 if (v.template is<T>())
304 return f(unwrapper<T>::apply_const(v.template get<T>()));
308 return dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
312 VARIANT_INLINE static R apply(V& v, F&& f)
314 if (v.template is<T>())
316 return f(unwrapper<T>::apply(v.template get<T>()));
320 return dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
325 template <typename F, typename V, typename R, typename T>
326 struct dispatcher<F, V, R, T>
328 VARIANT_INLINE static R apply_const(V const& v, F&& f)
330 return f(unwrapper<T>::apply_const(v.template get<T>()));
333 VARIANT_INLINE static R apply(V& v, F&& f)
335 return f(unwrapper<T>::apply(v.template get<T>()));
339 template <typename F, typename V, typename R, typename T, typename... Types>
340 struct binary_dispatcher_rhs;
342 template <typename F, typename V, typename R, typename T0, typename T1, typename... Types>
343 struct binary_dispatcher_rhs<F, V, R, T0, T1, Types...>
345 VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
347 if (rhs.template is<T1>()) // call binary functor
349 return f(unwrapper<T0>::apply_const(lhs.template get<T0>()),
350 unwrapper<T1>::apply_const(rhs.template get<T1>()));
354 return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f));
358 VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
360 if (rhs.template is<T1>()) // call binary functor
362 return f(unwrapper<T0>::apply(lhs.template get<T0>()),
363 unwrapper<T1>::apply(rhs.template get<T1>()));
367 return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f));
372 template <typename F, typename V, typename R, typename T0, typename T1>
373 struct binary_dispatcher_rhs<F, V, R, T0, T1>
375 VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
377 return f(unwrapper<T0>::apply_const(lhs.template get<T0>()),
378 unwrapper<T1>::apply_const(rhs.template get<T1>()));
381 VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
383 return f(unwrapper<T0>::apply(lhs.template get<T0>()),
384 unwrapper<T1>::apply(rhs.template get<T1>()));
388 template <typename F, typename V, typename R, typename T, typename... Types>
389 struct binary_dispatcher_lhs;
391 template <typename F, typename V, typename R, typename T0, typename T1, typename... Types>
392 struct binary_dispatcher_lhs<F, V, R, T0, T1, Types...>
394 VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
396 if (lhs.template is<T1>()) // call binary functor
398 return f(unwrapper<T1>::apply_const(lhs.template get<T1>()),
399 unwrapper<T0>::apply_const(rhs.template get<T0>()));
403 return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f));
407 VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
409 if (lhs.template is<T1>()) // call binary functor
411 return f(unwrapper<T1>::apply(lhs.template get<T1>()),
412 unwrapper<T0>::apply(rhs.template get<T0>()));
416 return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f));
421 template <typename F, typename V, typename R, typename T0, typename T1>
422 struct binary_dispatcher_lhs<F, V, R, T0, T1>
424 VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
426 return f(unwrapper<T1>::apply_const(lhs.template get<T1>()),
427 unwrapper<T0>::apply_const(rhs.template get<T0>()));
430 VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
432 return f(unwrapper<T1>::apply(lhs.template get<T1>()),
433 unwrapper<T0>::apply(rhs.template get<T0>()));
437 template <typename F, typename V, typename R, typename... Types>
438 struct binary_dispatcher;
440 template <typename F, typename V, typename R, typename T, typename... Types>
441 struct binary_dispatcher<F, V, R, T, Types...>
443 VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
445 if (v0.template is<T>())
447 if (v1.template is<T>())
449 return f(unwrapper<T>::apply_const(v0.template get<T>()),
450 unwrapper<T>::apply_const(v1.template get<T>())); // call binary functor
454 return binary_dispatcher_rhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f));
457 else if (v1.template is<T>())
459 return binary_dispatcher_lhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f));
461 return binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f));
464 VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
466 if (v0.template is<T>())
468 if (v1.template is<T>())
470 return f(unwrapper<T>::apply(v0.template get<T>()),
471 unwrapper<T>::apply(v1.template get<T>())); // call binary functor
475 return binary_dispatcher_rhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
478 else if (v1.template is<T>())
480 return binary_dispatcher_lhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
482 return binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
486 template <typename F, typename V, typename R, typename T>
487 struct binary_dispatcher<F, V, R, T>
489 VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
491 return f(unwrapper<T>::apply_const(v0.template get<T>()),
492 unwrapper<T>::apply_const(v1.template get<T>())); // call binary functor
495 VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
497 return f(unwrapper<T>::apply(v0.template get<T>()),
498 unwrapper<T>::apply(v1.template get<T>())); // call binary functor
502 // comparator functors
505 template <typename T>
506 bool operator()(T const& lhs, T const& rhs) const
514 template <typename T>
515 bool operator()(T const& lhs, T const& rhs) const
521 template <typename Variant, typename Comp>
525 explicit comparer(Variant const& lhs) noexcept
527 comparer& operator=(comparer const&) = delete;
529 template <typename T>
530 bool operator()(T const& rhs_content) const
532 T const& lhs_content = lhs_.template get<T>();
533 return Comp()(lhs_content, rhs_content);
540 // True if Predicate matches for all of the types Ts
541 template <template <typename> class Predicate, typename... Ts>
542 struct static_all_of : std::is_same<std::tuple<std::true_type, typename Predicate<Ts>::type...>,
543 std::tuple<typename Predicate<Ts>::type..., std::true_type>>
547 // True if Predicate matches for none of the types Ts
548 template <template <typename> class Predicate, typename... Ts>
549 struct static_none_of : std::is_same<std::tuple<std::false_type, typename Predicate<Ts>::type...>,
550 std::tuple<typename Predicate<Ts>::type..., std::false_type>>
554 } // namespace detail
560 template <typename... Types>
563 static_assert(sizeof...(Types) > 0, "Template parameter type list of variant can not be empty");
564 static_assert(detail::static_none_of<std::is_reference, Types...>::value, "Variant can not hold reference types. Maybe use std::reference?");
567 static const std::size_t data_size = detail::static_max<sizeof(Types)...>::value;
568 static const std::size_t data_align = detail::static_max<alignof(Types)...>::value;
570 using first_type = typename std::tuple_element<0, std::tuple<Types...>>::type;
571 using data_type = typename std::aligned_storage<data_size, data_align>::type;
572 using helper_type = detail::variant_helper<Types...>;
574 std::size_t type_index;
578 VARIANT_INLINE variant() noexcept(std::is_nothrow_default_constructible<first_type>::value)
579 : type_index(sizeof...(Types)-1)
581 static_assert(std::is_default_constructible<first_type>::value, "First type in variant must be default constructible to allow default construction of variant");
582 new (&data) first_type();
585 VARIANT_INLINE variant(no_init) noexcept
586 : type_index(detail::invalid_value) {}
588 // http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
589 template <typename T, typename Traits = detail::value_traits<T, Types...>,
590 typename Enable = typename std::enable_if<Traits::is_valid>::type>
591 VARIANT_INLINE variant(T&& val) noexcept(std::is_nothrow_constructible<typename Traits::target_type, T&&>::value)
592 : type_index(Traits::index)
594 new (&data) typename Traits::target_type(std::forward<T>(val));
597 VARIANT_INLINE variant(variant<Types...> const& old)
598 : type_index(old.type_index)
600 helper_type::copy(old.type_index, &old.data, &data);
603 VARIANT_INLINE variant(variant<Types...>&& old) noexcept(std::is_nothrow_move_constructible<std::tuple<Types...>>::value)
604 : type_index(old.type_index)
606 helper_type::move(old.type_index, &old.data, &data);
610 VARIANT_INLINE void copy_assign(variant<Types...> const& rhs)
612 helper_type::destroy(type_index, &data);
613 type_index = detail::invalid_value;
614 helper_type::copy(rhs.type_index, &rhs.data, &data);
615 type_index = rhs.type_index;
618 VARIANT_INLINE void move_assign(variant<Types...>&& rhs)
620 helper_type::destroy(type_index, &data);
621 type_index = detail::invalid_value;
622 helper_type::move(rhs.type_index, &rhs.data, &data);
623 type_index = rhs.type_index;
627 VARIANT_INLINE variant<Types...>& operator=(variant<Types...>&& other)
629 move_assign(std::move(other));
633 VARIANT_INLINE variant<Types...>& operator=(variant<Types...> const& other)
641 template <typename T>
642 VARIANT_INLINE variant<Types...>& operator=(T&& rhs) noexcept
644 variant<Types...> temp(std::forward<T>(rhs));
645 move_assign(std::move(temp));
650 template <typename T>
651 VARIANT_INLINE variant<Types...>& operator=(T const& rhs)
653 variant<Types...> temp(rhs);
658 template <typename T>
659 VARIANT_INLINE bool is() const
661 static_assert(detail::has_type<T, Types...>::value, "invalid type in T in `is<T>()` for this variant");
662 return type_index == detail::direct_type<T, Types...>::index;
665 VARIANT_INLINE bool valid() const
667 return type_index != detail::invalid_value;
670 template <typename T, typename... Args>
671 VARIANT_INLINE void set(Args&&... args)
673 helper_type::destroy(type_index, &data);
674 type_index = detail::invalid_value;
675 new (&data) T(std::forward<Args>(args)...);
676 type_index = detail::direct_type<T, Types...>::index;
680 template <typename T, typename std::enable_if<
681 (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
682 VARIANT_INLINE T& get()
684 if (type_index == detail::direct_type<T, Types...>::index)
686 return *reinterpret_cast<T*>(&data);
690 throw bad_variant_access("in get<T>()");
694 template <typename T, typename std::enable_if<
695 (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
696 VARIANT_INLINE T const& get() const
698 if (type_index == detail::direct_type<T, Types...>::index)
700 return *reinterpret_cast<T const*>(&data);
704 throw bad_variant_access("in get<T>()");
708 // get<T>() - T stored as recursive_wrapper<T>
709 template <typename T, typename std::enable_if<
710 (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
711 VARIANT_INLINE T& get()
713 if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
715 return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
719 throw bad_variant_access("in get<T>()");
723 template <typename T, typename std::enable_if<
724 (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
725 VARIANT_INLINE T const& get() const
727 if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
729 return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get();
733 throw bad_variant_access("in get<T>()");
737 // get<T>() - T stored as std::reference_wrapper<T>
738 template <typename T, typename std::enable_if<
739 (detail::direct_type<std::reference_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
740 VARIANT_INLINE T& get()
742 if (type_index == detail::direct_type<std::reference_wrapper<T>, Types...>::index)
744 return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
748 throw bad_variant_access("in get<T>()");
752 template <typename T, typename std::enable_if<
753 (detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)>::type* = nullptr>
754 VARIANT_INLINE T const& get() const
756 if (type_index == detail::direct_type<std::reference_wrapper<T const>, Types...>::index)
758 return (*reinterpret_cast<std::reference_wrapper<T const> const*>(&data)).get();
762 throw bad_variant_access("in get<T>()");
766 // This function is deprecated because it returns an internal index field.
767 // Use which() instead.
768 OPENTRACING_VARIANT_DEPRECATED VARIANT_INLINE std::size_t get_type_index() const
773 VARIANT_INLINE int which() const noexcept
775 return static_cast<int>(sizeof...(Types)-type_index - 1);
780 template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
781 auto VARIANT_INLINE static visit(V const& v, F&& f)
782 -> decltype(detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f)))
784 return detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
787 template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
788 auto VARIANT_INLINE static visit(V& v, F&& f)
789 -> decltype(detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f)))
791 return detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
796 template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type>
797 auto VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F&& f)
798 -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f)))
800 return detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f));
803 template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type>
804 auto VARIANT_INLINE static binary_visit(V& v0, V& v1, F&& f)
805 -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f)))
807 return detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
810 ~variant() noexcept // no-throw destructor
812 helper_type::destroy(type_index, &data);
815 // comparison operators
817 VARIANT_INLINE bool operator==(variant const& rhs) const
819 assert(valid() && rhs.valid());
820 if (this->which() != rhs.which())
824 detail::comparer<variant, detail::equal_comp> visitor(*this);
825 return visit(rhs, visitor);
828 VARIANT_INLINE bool operator!=(variant const& rhs) const
830 return !(*this == rhs);
834 VARIANT_INLINE bool operator<(variant const& rhs) const
836 assert(valid() && rhs.valid());
837 if (this->which() != rhs.which())
839 return this->which() < rhs.which();
841 detail::comparer<variant, detail::less_comp> visitor(*this);
842 return visit(rhs, visitor);
844 VARIANT_INLINE bool operator>(variant const& rhs) const
848 VARIANT_INLINE bool operator<=(variant const& rhs) const
850 return !(*this > rhs);
852 VARIANT_INLINE bool operator>=(variant const& rhs) const
854 return !(*this < rhs);
858 // unary visitor interface
860 template <typename F, typename V>
861 auto VARIANT_INLINE apply_visitor(F&& f, V const& v) -> decltype(V::visit(v, std::forward<F>(f)))
863 return V::visit(v, std::forward<F>(f));
867 template <typename F, typename V>
868 auto VARIANT_INLINE apply_visitor(F&& f, V& v) -> decltype(V::visit(v, std::forward<F>(f)))
870 return V::visit(v, std::forward<F>(f));
873 // binary visitor interface
875 template <typename F, typename V>
876 auto VARIANT_INLINE apply_visitor(F&& f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
878 return V::binary_visit(v0, v1, std::forward<F>(f));
882 template <typename F, typename V>
883 auto VARIANT_INLINE apply_visitor(F&& f, V& v0, V& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
885 return V::binary_visit(v0, v1, std::forward<F>(f));
889 template <typename ResultType, typename T>
890 ResultType& get(T& var)
892 return var.template get<ResultType>();
895 template <typename ResultType, typename T>
896 ResultType const& get(T const& var)
898 return var.template get<ResultType>();
901 END_OPENTRACING_ABI_NAMESPACE
902 } // namespace opentracing
904 #endif // OPENTRACING_UTIL_VARIANT_HPP