// MPark.Variant // // Copyright Michael Park, 2015-2017 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) #ifndef MPARK_VARIANT_HPP #define MPARK_VARIANT_HPP /* variant synopsis namespace std { // 20.7.2, class template variant template <class... Types> class variant { public: // 20.7.2.1, constructors constexpr variant() noexcept(see below); variant(const variant&); variant(variant&&) noexcept(see below); template <class T> constexpr variant(T&&) noexcept(see below); template <class T, class... Args> constexpr explicit variant(in_place_type_t<T>, Args&&...); template <class T, class U, class... Args> constexpr explicit variant( in_place_type_t<T>, initializer_list<U>, Args&&...); template <size_t I, class... Args> constexpr explicit variant(in_place_index_t<I>, Args&&...); template <size_t I, class U, class... Args> constexpr explicit variant( in_place_index_t<I>, initializer_list<U>, Args&&...); // 20.7.2.2, destructor ~variant(); // 20.7.2.3, assignment variant& operator=(const variant&); variant& operator=(variant&&) noexcept(see below); template <class T> variant& operator=(T&&) noexcept(see below); // 20.7.2.4, modifiers template <class T, class... Args> T& emplace(Args&&...); template <class T, class U, class... Args> T& emplace(initializer_list<U>, Args&&...); template <size_t I, class... Args> variant_alternative<I, variant>& emplace(Args&&...); template <size_t I, class U, class... Args> variant_alternative<I, variant>& emplace(initializer_list<U>, Args&&...); // 20.7.2.5, value status constexpr bool valueless_by_exception() const noexcept; constexpr size_t index() const noexcept; // 20.7.2.6, swap void swap(variant&) noexcept(see below); }; // 20.7.3, variant helper classes template <class T> struct variant_size; // undefined template <class T> constexpr size_t variant_size_v = variant_size<T>::value; template <class T> struct variant_size<const T>; template <class T> struct variant_size<volatile T>; template <class T> struct variant_size<const volatile T>; template <class... Types> struct variant_size<variant<Types...>>; template <size_t I, class T> struct variant_alternative; // undefined template <size_t I, class T> using variant_alternative_t = typename variant_alternative<I, T>::type; template <size_t I, class T> struct variant_alternative<I, const T>; template <size_t I, class T> struct variant_alternative<I, volatile T>; template <size_t I, class T> struct variant_alternative<I, const volatile T>; template <size_t I, class... Types> struct variant_alternative<I, variant<Types...>>; constexpr size_t variant_npos = -1; // 20.7.4, value access template <class T, class... Types> constexpr bool holds_alternative(const variant<Types...>&) noexcept; template <size_t I, class... Types> constexpr variant_alternative_t<I, variant<Types...>>& get(variant<Types...>&); template <size_t I, class... Types> constexpr variant_alternative_t<I, variant<Types...>>&& get(variant<Types...>&&); template <size_t I, class... Types> constexpr variant_alternative_t<I, variant<Types...>> const& get(const variant<Types...>&); template <size_t I, class... Types> constexpr variant_alternative_t<I, variant<Types...>> const&& get(const variant<Types...>&&); template <class T, class... Types> constexpr T& get(variant<Types...>&); template <class T, class... Types> constexpr T&& get(variant<Types...>&&); template <class T, class... Types> constexpr const T& get(const variant<Types...>&); template <class T, class... Types> constexpr const T&& get(const variant<Types...>&&); template <size_t I, class... Types> constexpr add_pointer_t<variant_alternative_t<I, variant<Types...>>> get_if(variant<Types...>*) noexcept; template <size_t I, class... Types> constexpr add_pointer_t<const variant_alternative_t<I, variant<Types...>>> get_if(const variant<Types...>*) noexcept; template <class T, class... Types> constexpr add_pointer_t<T> get_if(variant<Types...>*) noexcept; template <class T, class... Types> constexpr add_pointer_t<const T> get_if(const variant<Types...>*) noexcept; // 20.7.5, relational operators template <class... Types> constexpr bool operator==(const variant<Types...>&, const variant<Types...>&); template <class... Types> constexpr bool operator!=(const variant<Types...>&, const variant<Types...>&); template <class... Types> constexpr bool operator<(const variant<Types...>&, const variant<Types...>&); template <class... Types> constexpr bool operator>(const variant<Types...>&, const variant<Types...>&); template <class... Types> constexpr bool operator<=(const variant<Types...>&, const variant<Types...>&); template <class... Types> constexpr bool operator>=(const variant<Types...>&, const variant<Types...>&); // 20.7.6, visitation template <class Visitor, class... Variants> constexpr see below visit(Visitor&&, Variants&&...); // 20.7.7, class monostate struct monostate; // 20.7.8, monostate relational operators constexpr bool operator<(monostate, monostate) noexcept; constexpr bool operator>(monostate, monostate) noexcept; constexpr bool operator<=(monostate, monostate) noexcept; constexpr bool operator>=(monostate, monostate) noexcept; constexpr bool operator==(monostate, monostate) noexcept; constexpr bool operator!=(monostate, monostate) noexcept; // 20.7.9, specialized algorithms template <class... Types> void swap(variant<Types...>&, variant<Types...>&) noexcept(see below); // 20.7.10, class bad_variant_access class bad_variant_access; // 20.7.11, hash support template <class T> struct hash; template <class... Types> struct hash<variant<Types...>>; template <> struct hash<monostate>; } // namespace std */ #include <cstddef> #include <exception> #include <functional> #include <initializer_list> #include <new> #include <type_traits> #include <utility> // MPark.Variant // // Copyright Michael Park, 2015-2017 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) #ifndef MPARK_CONFIG_HPP #define MPARK_CONFIG_HPP // MSVC 2015 Update 3. #if __cplusplus < 201103L && (!defined(_MSC_VER) || _MSC_FULL_VER < 190024210) #error "MPark.Variant requires C++11 support." #endif #ifndef __has_attribute #define __has_attribute(x) 0 #endif #ifndef __has_builtin #define __has_builtin(x) 0 #endif #ifndef __has_include #define __has_include(x) 0 #endif #ifndef __has_feature #define __has_feature(x) 0 #endif #if __has_attribute(always_inline) || defined(__GNUC__) #define MPARK_ALWAYS_INLINE __attribute__((__always_inline__)) inline #elif defined(_MSC_VER) #define MPARK_ALWAYS_INLINE __forceinline #else #define MPARK_ALWAYS_INLINE inline #endif #if __has_builtin(__builtin_addressof) || \ (defined(__GNUC__) && __GNUC__ >= 7) || defined(_MSC_VER) #define MPARK_BUILTIN_ADDRESSOF #endif #if __has_builtin(__builtin_unreachable) || defined(__GNUC__) #define MPARK_BUILTIN_UNREACHABLE __builtin_unreachable() #elif defined(_MSC_VER) #define MPARK_BUILTIN_UNREACHABLE __assume(false) #else #define MPARK_BUILTIN_UNREACHABLE #endif #if __has_builtin(__type_pack_element) #define MPARK_TYPE_PACK_ELEMENT #endif #if defined(__cpp_constexpr) && __cpp_constexpr >= 200704 && \ !(defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 9) #define MPARK_CPP11_CONSTEXPR #endif #if defined(__cpp_constexpr) && __cpp_constexpr >= 201304 #define MPARK_CPP14_CONSTEXPR #endif #if __has_feature(cxx_exceptions) || defined(__cpp_exceptions) || \ (defined(_MSC_VER) && defined(_CPPUNWIND)) #define MPARK_EXCEPTIONS #endif #if defined(__cpp_generic_lambdas) || defined(_MSC_VER) #define MPARK_GENERIC_LAMBDAS #endif #if defined(__cpp_lib_integer_sequence) #define MPARK_INTEGER_SEQUENCE #endif #if defined(__cpp_return_type_deduction) || defined(_MSC_VER) #define MPARK_RETURN_TYPE_DEDUCTION #endif #if defined(__cpp_lib_transparent_operators) || defined(_MSC_VER) #define MPARK_TRANSPARENT_OPERATORS #endif #if defined(__cpp_variable_templates) || defined(_MSC_VER) #define MPARK_VARIABLE_TEMPLATES #endif #if !defined(__GLIBCXX__) || __has_include(<codecvt>) // >= libstdc++-5 #define MPARK_TRIVIALITY_TYPE_TRAITS #define MPARK_INCOMPLETE_TYPE_TRAITS #endif #endif // MPARK_CONFIG_HPP // MPark.Variant // // Copyright Michael Park, 2015-2017 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) #ifndef MPARK_IN_PLACE_HPP #define MPARK_IN_PLACE_HPP #include <cstddef> namespace mpark { struct in_place_t { explicit in_place_t() = default; }; template <std::size_t I> struct in_place_index_t { explicit in_place_index_t() = default; }; template <typename T> struct in_place_type_t { explicit in_place_type_t() = default; }; #ifdef MPARK_VARIABLE_TEMPLATES constexpr in_place_t in_place{}; template <std::size_t I> constexpr in_place_index_t<I> in_place_index{}; template <typename T> constexpr in_place_type_t<T> in_place_type{}; #endif } // namespace mpark #endif // MPARK_IN_PLACE_HPP // MPark.Variant // // Copyright Michael Park, 2015-2017 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) #ifndef MPARK_LIB_HPP #define MPARK_LIB_HPP #include <memory> #include <functional> #include <type_traits> #include <utility> #define MPARK_RETURN(...) \ noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) { return __VA_ARGS__; } namespace mpark { namespace lib { template <typename T> struct identity { using type = T; }; inline namespace cpp14 { template <typename T, std::size_t N> struct array { constexpr const T &operator[](std::size_t index) const { return data[index]; } T data[N == 0 ? 1 : N]; }; template <typename T> using add_pointer_t = typename std::add_pointer<T>::type; template <typename... Ts> using common_type_t = typename std::common_type<Ts...>::type; template <typename T> using decay_t = typename std::decay<T>::type; template <bool B, typename T = void> using enable_if_t = typename std::enable_if<B, T>::type; template <typename T> using remove_const_t = typename std::remove_const<T>::type; template <typename T> using remove_reference_t = typename std::remove_reference<T>::type; template <typename T> inline constexpr T &&forward(remove_reference_t<T> &t) noexcept { return static_cast<T &&>(t); } template <typename T> inline constexpr T &&forward(remove_reference_t<T> &&t) noexcept { static_assert(!std::is_lvalue_reference<T>::value, "can not forward an rvalue as an lvalue"); return static_cast<T &&>(t); } template <typename T> inline constexpr remove_reference_t<T> &&move(T &&t) noexcept { return static_cast<remove_reference_t<T> &&>(t); } #ifdef MPARK_INTEGER_SEQUENCE using std::integer_sequence; using std::index_sequence; using std::make_index_sequence; using std::index_sequence_for; #else template <typename T, T... Is> struct integer_sequence { using value_type = T; static constexpr std::size_t size() noexcept { return sizeof...(Is); } }; template <std::size_t... Is> using index_sequence = integer_sequence<std::size_t, Is...>; template <typename Lhs, typename Rhs> struct make_index_sequence_concat; template <std::size_t... Lhs, std::size_t... Rhs> struct make_index_sequence_concat<index_sequence<Lhs...>, index_sequence<Rhs...>> : identity<index_sequence<Lhs..., (sizeof...(Lhs) + Rhs)...>> {}; template <std::size_t N> struct make_index_sequence_impl; template <std::size_t N> using make_index_sequence = typename make_index_sequence_impl<N>::type; template <std::size_t N> struct make_index_sequence_impl : make_index_sequence_concat<make_index_sequence<N / 2>, make_index_sequence<N - (N / 2)>> {}; template <> struct make_index_sequence_impl<0> : identity<index_sequence<>> {}; template <> struct make_index_sequence_impl<1> : identity<index_sequence<0>> {}; template <typename... Ts> using index_sequence_for = make_index_sequence<sizeof...(Ts)>; #endif // <functional> #ifdef MPARK_TRANSPARENT_OPERATORS using equal_to = std::equal_to<>; #else struct equal_to { template <typename Lhs, typename Rhs> inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const MPARK_RETURN(lib::forward<Lhs>(lhs) == lib::forward<Rhs>(rhs)) }; #endif #ifdef MPARK_TRANSPARENT_OPERATORS using not_equal_to = std::not_equal_to<>; #else struct not_equal_to { template <typename Lhs, typename Rhs> inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const MPARK_RETURN(lib::forward<Lhs>(lhs) != lib::forward<Rhs>(rhs)) }; #endif #ifdef MPARK_TRANSPARENT_OPERATORS using less = std::less<>; #else struct less { template <typename Lhs, typename Rhs> inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const MPARK_RETURN(lib::forward<Lhs>(lhs) < lib::forward<Rhs>(rhs)) }; #endif #ifdef MPARK_TRANSPARENT_OPERATORS using greater = std::greater<>; #else struct greater { template <typename Lhs, typename Rhs> inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const MPARK_RETURN(lib::forward<Lhs>(lhs) > lib::forward<Rhs>(rhs)) }; #endif #ifdef MPARK_TRANSPARENT_OPERATORS using less_equal = std::less_equal<>; #else struct less_equal { template <typename Lhs, typename Rhs> inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const MPARK_RETURN(lib::forward<Lhs>(lhs) <= lib::forward<Rhs>(rhs)) }; #endif #ifdef MPARK_TRANSPARENT_OPERATORS using greater_equal = std::greater_equal<>; #else struct greater_equal { template <typename Lhs, typename Rhs> inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const MPARK_RETURN(lib::forward<Lhs>(lhs) >= lib::forward<Rhs>(rhs)) }; #endif } // namespace cpp14 inline namespace cpp17 { // <type_traits> template <bool B> using bool_constant = std::integral_constant<bool, B>; template <typename...> struct voider : identity<void> {}; template <typename... Ts> using void_t = typename voider<Ts...>::type; namespace detail { namespace swappable { using std::swap; template <typename T> struct is_swappable { private: template <typename U, typename = decltype(swap(std::declval<U &>(), std::declval<U &>()))> inline static std::true_type test(int); template <typename U> inline static std::false_type test(...); public: static constexpr bool value = decltype(test<T>(0))::value; }; template <bool IsSwappable, typename T> struct is_nothrow_swappable { static constexpr bool value = noexcept(swap(std::declval<T &>(), std::declval<T &>())); }; template <typename T> struct is_nothrow_swappable<false, T> : std::false_type {}; } // namespace swappable } // namespace detail using detail::swappable::is_swappable; template <typename T> using is_nothrow_swappable = detail::swappable::is_nothrow_swappable<is_swappable<T>::value, T>; // <functional> namespace detail { template <typename T> struct is_reference_wrapper : std::false_type {}; template <typename T> struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {}; template <bool, int> struct Invoke; template <> struct Invoke<true /* pmf */, 0 /* is_base_of */> { template <typename R, typename T, typename Arg, typename... Args> inline static constexpr auto invoke(R T::*pmf, Arg &&arg, Args &&... args) MPARK_RETURN((lib::forward<Arg>(arg).*pmf)(lib::forward<Args>(args)...)) }; template <> struct Invoke<true /* pmf */, 1 /* is_reference_wrapper */> { template <typename R, typename T, typename Arg, typename... Args> inline static constexpr auto invoke(R T::*pmf, Arg &&arg, Args &&... args) MPARK_RETURN((lib::forward<Arg>(arg).get().*pmf)(lib::forward<Args>(args)...)) }; template <> struct Invoke<true /* pmf */, 2 /* otherwise */> { template <typename R, typename T, typename Arg, typename... Args> inline static constexpr auto invoke(R T::*pmf, Arg &&arg, Args &&... args) MPARK_RETURN(((*lib::forward<Arg>(arg)).*pmf)(lib::forward<Args>(args)...)) }; template <> struct Invoke<false /* pmo */, 0 /* is_base_of */> { template <typename R, typename T, typename Arg> inline static constexpr auto invoke(R T::*pmo, Arg &&arg) MPARK_RETURN(lib::forward<Arg>(arg).*pmo) }; template <> struct Invoke<false /* pmo */, 1 /* is_reference_wrapper */> { template <typename R, typename T, typename Arg> inline static constexpr auto invoke(R T::*pmo, Arg &&arg) MPARK_RETURN(lib::forward<Arg>(arg).get().*pmo) }; template <> struct Invoke<false /* pmo */, 2 /* otherwise */> { template <typename R, typename T, typename Arg> inline static constexpr auto invoke(R T::*pmo, Arg &&arg) MPARK_RETURN((*lib::forward<Arg>(arg)).*pmo) }; template <typename R, typename T, typename Arg, typename... Args> inline constexpr auto invoke(R T::*f, Arg &&arg, Args &&... args) MPARK_RETURN( Invoke<std::is_function<R>::value, (std::is_base_of<T, lib::decay_t<Arg>>::value ? 0 : is_reference_wrapper<lib::decay_t<Arg>>::value ? 1 : 2)>::invoke(f, lib::forward<Arg>(arg), lib::forward<Args>(args)...)) #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4100) #endif template <typename F, typename... Args> inline constexpr auto invoke(F &&f, Args &&... args) MPARK_RETURN(lib::forward<F>(f)(lib::forward<Args>(args)...)) #ifdef _MSC_VER #pragma warning(pop) #endif } // namespace detail template <typename F, typename... Args> inline constexpr auto invoke(F &&f, Args &&... args) MPARK_RETURN(detail::invoke(lib::forward<F>(f), lib::forward<Args>(args)...)) namespace detail { template <typename Void, typename, typename...> struct invoke_result {}; template <typename F, typename... Args> struct invoke_result<void_t<decltype(lib::invoke( std::declval<F>(), std::declval<Args>()...))>, F, Args...> : identity<decltype( lib::invoke(std::declval<F>(), std::declval<Args>()...))> {}; } // namespace detail template <typename F, typename... Args> using invoke_result = detail::invoke_result<void, F, Args...>; template <typename F, typename... Args> using invoke_result_t = typename invoke_result<F, Args...>::type; namespace detail { template <typename Void, typename, typename...> struct is_invocable : std::false_type {}; template <typename F, typename... Args> struct is_invocable<void_t<invoke_result_t<F, Args...>>, F, Args...> : std::true_type {}; template <typename Void, typename, typename, typename...> struct is_invocable_r : std::false_type {}; template <typename R, typename F, typename... Args> struct is_invocable_r<void_t<invoke_result_t<F, Args...>>, R, F, Args...> : std::is_convertible<invoke_result_t<F, Args...>, R> {}; } // namespace detail template <typename F, typename... Args> using is_invocable = detail::is_invocable<void, F, Args...>; template <typename R, typename F, typename... Args> using is_invocable_r = detail::is_invocable_r<void, R, F, Args...>; namespace detail { template <bool Invocable, typename F, typename... Args> struct is_nothrow_invocable { static constexpr bool value = noexcept(lib::invoke(std::declval<F>(), std::declval<Args>()...)); }; template <typename F, typename... Args> struct is_nothrow_invocable<false, F, Args...> : std::false_type {}; template <bool Invocable, typename R, typename F, typename... Args> struct is_nothrow_invocable_r { private: inline static R impl() { return lib::invoke(std::declval<F>(), std::declval<Args>()...); } public: static constexpr bool value = noexcept(impl()); }; template <typename R, typename F, typename... Args> struct is_nothrow_invocable_r<false, R, F, Args...> : std::false_type {}; } // namespace detail template <typename F, typename... Args> using is_nothrow_invocable = detail:: is_nothrow_invocable<is_invocable<F, Args...>::value, F, Args...>; template <typename R, typename F, typename... Args> using is_nothrow_invocable_r = detail::is_nothrow_invocable_r<is_invocable_r<R, F, Args...>::value, R, F, Args...>; // <memory> #ifdef MPARK_BUILTIN_ADDRESSOF template <typename T> inline constexpr T *addressof(T &arg) noexcept { return __builtin_addressof(arg); } #else namespace detail { namespace has_addressof_impl { struct fail; template <typename T> inline fail operator&(T &&); template <typename T> inline static constexpr bool impl() { return (std::is_class<T>::value || std::is_union<T>::value) && !std::is_same<decltype(&std::declval<T &>()), fail>::value; } } // namespace has_addressof_impl template <typename T> using has_addressof = bool_constant<has_addressof_impl::impl<T>()>; template <typename T> inline constexpr T *addressof(T &arg, std::true_type) noexcept { return std::addressof(arg); } template <typename T> inline constexpr T *addressof(T &arg, std::false_type) noexcept { return &arg; } } // namespace detail template <typename T> inline constexpr T *addressof(T &arg) noexcept { return detail::addressof(arg, detail::has_addressof<T>{}); } #endif template <typename T> inline constexpr T *addressof(const T &&) = delete; } // namespace cpp17 template <typename T> struct remove_all_extents : identity<T> {}; template <typename T, std::size_t N> struct remove_all_extents<array<T, N>> : remove_all_extents<T> {}; template <typename T> using remove_all_extents_t = typename remove_all_extents<T>::type; template <std::size_t N> using size_constant = std::integral_constant<std::size_t, N>; template <std::size_t I, typename T> struct indexed_type : size_constant<I> { using type = T; }; template <bool... Bs> using all = std::is_same<integer_sequence<bool, true, Bs...>, integer_sequence<bool, Bs..., true>>; #ifdef MPARK_TYPE_PACK_ELEMENT template <std::size_t I, typename... Ts> using type_pack_element_t = __type_pack_element<I, Ts...>; #else template <std::size_t I, typename... Ts> struct type_pack_element_impl { private: template <typename> struct set; template <std::size_t... Is> struct set<index_sequence<Is...>> : indexed_type<Is, Ts>... {}; template <typename T> inline static std::enable_if<true, T> impl(indexed_type<I, T>); inline static std::enable_if<false> impl(...); public: using type = decltype(impl(set<index_sequence_for<Ts...>>{})); }; template <std::size_t I, typename... Ts> using type_pack_element = typename type_pack_element_impl<I, Ts...>::type; template <std::size_t I, typename... Ts> using type_pack_element_t = typename type_pack_element<I, Ts...>::type; #endif #ifdef MPARK_TRIVIALITY_TYPE_TRAITS using std::is_trivially_copy_constructible; using std::is_trivially_move_constructible; using std::is_trivially_copy_assignable; using std::is_trivially_move_assignable; #else template <typename T> struct is_trivially_copy_constructible : bool_constant< std::is_copy_constructible<T>::value && __has_trivial_copy(T)> {}; template <typename T> struct is_trivially_move_constructible : bool_constant<__is_trivial(T)> {}; template <typename T> struct is_trivially_copy_assignable : bool_constant< std::is_copy_assignable<T>::value && __has_trivial_assign(T)> {}; template <typename T> struct is_trivially_move_assignable : bool_constant<__is_trivial(T)> {}; #endif template <typename T, bool> struct dependent_type : T {}; template <typename Is, std::size_t J> struct push_back; template <typename Is, std::size_t J> using push_back_t = typename push_back<Is, J>::type; template <std::size_t... Is, std::size_t J> struct push_back<index_sequence<Is...>, J> { using type = index_sequence<Is..., J>; }; } // namespace lib } // namespace mpark #undef MPARK_RETURN #endif // MPARK_LIB_HPP namespace mpark { #ifdef MPARK_RETURN_TYPE_DEDUCTION #define AUTO auto #define AUTO_RETURN(...) { return __VA_ARGS__; } #define AUTO_REFREF auto && #define AUTO_REFREF_RETURN(...) { return __VA_ARGS__; } #define DECLTYPE_AUTO decltype(auto) #define DECLTYPE_AUTO_RETURN(...) { return __VA_ARGS__; } #else #define AUTO auto #define AUTO_RETURN(...) \ -> lib::decay_t<decltype(__VA_ARGS__)> { return __VA_ARGS__; } #define AUTO_REFREF auto #define AUTO_REFREF_RETURN(...) \ -> decltype((__VA_ARGS__)) { \ static_assert(std::is_reference<decltype((__VA_ARGS__))>::value, ""); \ return __VA_ARGS__; \ } #define DECLTYPE_AUTO auto #define DECLTYPE_AUTO_RETURN(...) \ -> decltype(__VA_ARGS__) { return __VA_ARGS__; } #endif class bad_variant_access : public std::exception { public: virtual const char *what() const noexcept override { return "bad_variant_access"; } }; [[noreturn]] inline void throw_bad_variant_access() { #ifdef MPARK_EXCEPTIONS throw bad_variant_access{}; #else std::terminate(); MPARK_BUILTIN_UNREACHABLE; #endif } template <typename... Ts> class variant; template <typename T> struct variant_size; #ifdef MPARK_VARIABLE_TEMPLATES template <typename T> constexpr std::size_t variant_size_v = variant_size<T>::value; #endif template <typename T> struct variant_size<const T> : variant_size<T> {}; template <typename T> struct variant_size<volatile T> : variant_size<T> {}; template <typename T> struct variant_size<const volatile T> : variant_size<T> {}; template <typename... Ts> struct variant_size<variant<Ts...>> : lib::size_constant<sizeof...(Ts)> {}; template <std::size_t I, typename T> struct variant_alternative; template <std::size_t I, typename T> using variant_alternative_t = typename variant_alternative<I, T>::type; template <std::size_t I, typename T> struct variant_alternative<I, const T> : std::add_const<variant_alternative_t<I, T>> {}; template <std::size_t I, typename T> struct variant_alternative<I, volatile T> : std::add_volatile<variant_alternative_t<I, T>> {}; template <std::size_t I, typename T> struct variant_alternative<I, const volatile T> : std::add_cv<variant_alternative_t<I, T>> {}; template <std::size_t I, typename... Ts> struct variant_alternative<I, variant<Ts...>> { static_assert(I < sizeof...(Ts), "index out of bounds in `std::variant_alternative<>`"); using type = lib::type_pack_element_t<I, Ts...>; }; constexpr std::size_t variant_npos = static_cast<std::size_t>(-1); namespace detail { constexpr std::size_t not_found = static_cast<std::size_t>(-1); constexpr std::size_t ambiguous = static_cast<std::size_t>(-2); #ifdef MPARK_CPP14_CONSTEXPR template <typename T, typename... Ts> inline constexpr std::size_t find_index() { constexpr lib::array<bool, sizeof...(Ts)> matches = { {std::is_same<T, Ts>::value...} }; std::size_t result = not_found; for (std::size_t i = 0; i < sizeof...(Ts); ++i) { if (matches[i]) { if (result != not_found) { return ambiguous; } result = i; } } return result; } #else inline constexpr std::size_t find_index_impl(std::size_t result, std::size_t) { return result; } template <typename... Bs> inline constexpr std::size_t find_index_impl(std::size_t result, std::size_t idx, bool b, Bs... bs) { return b ? (result != not_found ? ambiguous : find_index_impl(idx, idx + 1, bs...)) : find_index_impl(result, idx + 1, bs...); } template <typename T, typename... Ts> inline constexpr std::size_t find_index() { return find_index_impl(not_found, 0, std::is_same<T, Ts>::value...); } #endif template <std::size_t I> using find_index_sfinae_impl = lib::enable_if_t<I != not_found && I != ambiguous, lib::size_constant<I>>; template <typename T, typename... Ts> using find_index_sfinae = find_index_sfinae_impl<find_index<T, Ts...>()>; template <std::size_t I> struct find_index_checked_impl : lib::size_constant<I> { static_assert(I != not_found, "the specified type is not found."); static_assert(I != ambiguous, "the specified type is ambiguous."); }; template <typename T, typename... Ts> using find_index_checked = find_index_checked_impl<find_index<T, Ts...>()>; struct valueless_t {}; enum class Trait { TriviallyAvailable, Available, Unavailable }; template <typename T, template <typename> class IsTriviallyAvailable, template <typename> class IsAvailable> inline constexpr Trait trait() { return IsTriviallyAvailable<T>::value ? Trait::TriviallyAvailable : IsAvailable<T>::value ? Trait::Available : Trait::Unavailable; } #ifdef MPARK_CPP14_CONSTEXPR template <typename... Traits> inline constexpr Trait common_trait(Traits... traits_) { Trait result = Trait::TriviallyAvailable; lib::array<Trait, sizeof...(Traits)> traits = {{traits_...}}; for (std::size_t i = 0; i < sizeof...(Traits); ++i) { Trait t = traits[i]; if (static_cast<int>(t) > static_cast<int>(result)) { result = t; } } return result; } #else inline constexpr Trait common_trait_impl(Trait result) { return result; } template <typename... Traits> inline constexpr Trait common_trait_impl(Trait result, Trait t, Traits... ts) { return static_cast<int>(t) > static_cast<int>(result) ? common_trait_impl(t, ts...) : common_trait_impl(result, ts...); } template <typename... Traits> inline constexpr Trait common_trait(Traits... ts) { return common_trait_impl(Trait::TriviallyAvailable, ts...); } #endif template <typename... Ts> struct traits { static constexpr Trait copy_constructible_trait = common_trait(trait<Ts, lib::is_trivially_copy_constructible, std::is_copy_constructible>()...); static constexpr Trait move_constructible_trait = common_trait(trait<Ts, lib::is_trivially_move_constructible, std::is_move_constructible>()...); static constexpr Trait copy_assignable_trait = common_trait(copy_constructible_trait, trait<Ts, lib::is_trivially_copy_assignable, std::is_copy_assignable>()...); static constexpr Trait move_assignable_trait = common_trait(move_constructible_trait, trait<Ts, lib::is_trivially_move_assignable, std::is_move_assignable>()...); static constexpr Trait destructible_trait = common_trait(trait<Ts, std::is_trivially_destructible, std::is_destructible>()...); }; namespace access { struct recursive_union { #ifdef MPARK_RETURN_TYPE_DEDUCTION template <typename V> inline static constexpr auto &&get_alt(V &&v, in_place_index_t<0>) { return lib::forward<V>(v).head_; } template <typename V, std::size_t I> inline static constexpr auto &&get_alt(V &&v, in_place_index_t<I>) { return get_alt(lib::forward<V>(v).tail_, in_place_index_t<I - 1>{}); } #else template <std::size_t I, bool Dummy = true> struct get_alt_impl { template <typename V> inline constexpr AUTO_REFREF operator()(V &&v) const AUTO_REFREF_RETURN(get_alt_impl<I - 1>{}(lib::forward<V>(v).tail_)) }; template <bool Dummy> struct get_alt_impl<0, Dummy> { template <typename V> inline constexpr AUTO_REFREF operator()(V &&v) const AUTO_REFREF_RETURN(lib::forward<V>(v).head_) }; template <typename V, std::size_t I> inline static constexpr AUTO_REFREF get_alt(V &&v, in_place_index_t<I>) AUTO_REFREF_RETURN(get_alt_impl<I>{}(lib::forward<V>(v))) #endif }; struct base { template <std::size_t I, typename V> inline static constexpr AUTO_REFREF get_alt(V &&v) #ifdef _MSC_VER AUTO_REFREF_RETURN(recursive_union::get_alt( lib::forward<V>(v).data_, in_place_index_t<I>{})) #else AUTO_REFREF_RETURN(recursive_union::get_alt( data(lib::forward<V>(v)), in_place_index_t<I>{})) #endif }; struct variant { template <std::size_t I, typename V> inline static constexpr AUTO_REFREF get_alt(V &&v) AUTO_REFREF_RETURN(base::get_alt<I>(lib::forward<V>(v).impl_)) }; } // namespace access namespace visitation { #if defined(MPARK_CPP14_CONSTEXPR) && !defined(_MSC_VER) #define MPARK_VARIANT_SWITCH_VISIT #endif struct base { template <typename Visitor, typename... Vs> using dispatch_result_t = decltype( lib::invoke(std::declval<Visitor>(), access::base::get_alt<0>(std::declval<Vs>())...)); template <typename Expected> struct expected { template <typename Actual> inline static constexpr bool but_got() { return std::is_same<Expected, Actual>::value; } }; template <typename Expected, typename Actual> struct visit_return_type_check { static_assert( expected<Expected>::template but_got<Actual>(), "`visit` requires the visitor to have a single return type"); template <typename Visitor, typename... Alts> inline static constexpr DECLTYPE_AUTO invoke(Visitor &&visitor, Alts &&... alts) DECLTYPE_AUTO_RETURN(lib::invoke(lib::forward<Visitor>(visitor), lib::forward<Alts>(alts)...)) }; #ifdef MPARK_VARIANT_SWITCH_VISIT template <bool B, typename R, typename... ITs> struct dispatcher; template <typename R, typename... ITs> struct dispatcher<false, R, ITs...> { template <std::size_t B, typename F, typename... Vs> MPARK_ALWAYS_INLINE static constexpr R dispatch( F &&, typename ITs::type &&..., Vs &&...) { MPARK_BUILTIN_UNREACHABLE; } template <std::size_t I, typename F, typename... Vs> MPARK_ALWAYS_INLINE static constexpr R dispatch_case(F &&, Vs &&...) { MPARK_BUILTIN_UNREACHABLE; } template <std::size_t B, typename F, typename... Vs> MPARK_ALWAYS_INLINE static constexpr R dispatch_at(std::size_t, F &&, Vs &&...) { MPARK_BUILTIN_UNREACHABLE; } }; template <typename R, typename... ITs> struct dispatcher<true, R, ITs...> { template <std::size_t B, typename F> MPARK_ALWAYS_INLINE static constexpr R dispatch( F &&f, typename ITs::type &&... visited_vs) { using Expected = R; using Actual = decltype(lib::invoke( lib::forward<F>(f), access::base::get_alt<ITs::value>( lib::forward<typename ITs::type>(visited_vs))...)); return visit_return_type_check<Expected, Actual>::invoke( lib::forward<F>(f), access::base::get_alt<ITs::value>( lib::forward<typename ITs::type>(visited_vs))...); } template <std::size_t B, typename F, typename V, typename... Vs> MPARK_ALWAYS_INLINE static constexpr R dispatch( F &&f, typename ITs::type &&... visited_vs, V &&v, Vs &&... vs) { #define MPARK_DISPATCH(I) \ dispatcher<(I < lib::decay_t<V>::size()), \ R, \ ITs..., \ lib::indexed_type<I, V>>:: \ template dispatch<0>(lib::forward<F>(f), \ lib::forward<typename ITs::type>(visited_vs)..., \ lib::forward<V>(v), \ lib::forward<Vs>(vs)...) #define MPARK_DEFAULT(I) \ dispatcher<(I < lib::decay_t<V>::size()), R, ITs...>::template dispatch<I>( \ lib::forward<F>(f), \ lib::forward<typename ITs::type>(visited_vs)..., \ lib::forward<V>(v), \ lib::forward<Vs>(vs)...) switch (v.index()) { case B + 0: return MPARK_DISPATCH(B + 0); case B + 1: return MPARK_DISPATCH(B + 1); case B + 2: return MPARK_DISPATCH(B + 2); case B + 3: return MPARK_DISPATCH(B + 3); case B + 4: return MPARK_DISPATCH(B + 4); case B + 5: return MPARK_DISPATCH(B + 5); case B + 6: return MPARK_DISPATCH(B + 6); case B + 7: return MPARK_DISPATCH(B + 7); case B + 8: return MPARK_DISPATCH(B + 8); case B + 9: return MPARK_DISPATCH(B + 9); case B + 10: return MPARK_DISPATCH(B + 10); case B + 11: return MPARK_DISPATCH(B + 11); case B + 12: return MPARK_DISPATCH(B + 12); case B + 13: return MPARK_DISPATCH(B + 13); case B + 14: return MPARK_DISPATCH(B + 14); case B + 15: return MPARK_DISPATCH(B + 15); case B + 16: return MPARK_DISPATCH(B + 16); case B + 17: return MPARK_DISPATCH(B + 17); case B + 18: return MPARK_DISPATCH(B + 18); case B + 19: return MPARK_DISPATCH(B + 19); case B + 20: return MPARK_DISPATCH(B + 20); case B + 21: return MPARK_DISPATCH(B + 21); case B + 22: return MPARK_DISPATCH(B + 22); case B + 23: return MPARK_DISPATCH(B + 23); case B + 24: return MPARK_DISPATCH(B + 24); case B + 25: return MPARK_DISPATCH(B + 25); case B + 26: return MPARK_DISPATCH(B + 26); case B + 27: return MPARK_DISPATCH(B + 27); case B + 28: return MPARK_DISPATCH(B + 28); case B + 29: return MPARK_DISPATCH(B + 29); case B + 30: return MPARK_DISPATCH(B + 30); case B + 31: return MPARK_DISPATCH(B + 31); default: return MPARK_DEFAULT(B + 32); } #undef MPARK_DEFAULT #undef MPARK_DISPATCH } template <std::size_t I, typename F, typename... Vs> MPARK_ALWAYS_INLINE static constexpr R dispatch_case(F &&f, Vs &&... vs) { using Expected = R; using Actual = decltype( lib::invoke(lib::forward<F>(f), access::base::get_alt<I>(lib::forward<Vs>(vs))...)); return visit_return_type_check<Expected, Actual>::invoke( lib::forward<F>(f), access::base::get_alt<I>(lib::forward<Vs>(vs))...); } template <std::size_t B, typename F, typename V, typename... Vs> MPARK_ALWAYS_INLINE static constexpr R dispatch_at(std::size_t index, F &&f, V &&v, Vs &&... vs) { static_assert(lib::all<(lib::decay_t<V>::size() == lib::decay_t<Vs>::size())...>::value, "all of the variants must be the same size."); #define MPARK_DISPATCH_AT(I) \ dispatcher<(I < lib::decay_t<V>::size()), R>::template dispatch_case<I>( \ lib::forward<F>(f), lib::forward<V>(v), lib::forward<Vs>(vs)...) #define MPARK_DEFAULT(I) \ dispatcher<(I < lib::decay_t<V>::size()), R>::template dispatch_at<I>( \ index, lib::forward<F>(f), lib::forward<V>(v), lib::forward<Vs>(vs)...) switch (index) { case B + 0: return MPARK_DISPATCH_AT(B + 0); case B + 1: return MPARK_DISPATCH_AT(B + 1); case B + 2: return MPARK_DISPATCH_AT(B + 2); case B + 3: return MPARK_DISPATCH_AT(B + 3); case B + 4: return MPARK_DISPATCH_AT(B + 4); case B + 5: return MPARK_DISPATCH_AT(B + 5); case B + 6: return MPARK_DISPATCH_AT(B + 6); case B + 7: return MPARK_DISPATCH_AT(B + 7); case B + 8: return MPARK_DISPATCH_AT(B + 8); case B + 9: return MPARK_DISPATCH_AT(B + 9); case B + 10: return MPARK_DISPATCH_AT(B + 10); case B + 11: return MPARK_DISPATCH_AT(B + 11); case B + 12: return MPARK_DISPATCH_AT(B + 12); case B + 13: return MPARK_DISPATCH_AT(B + 13); case B + 14: return MPARK_DISPATCH_AT(B + 14); case B + 15: return MPARK_DISPATCH_AT(B + 15); case B + 16: return MPARK_DISPATCH_AT(B + 16); case B + 17: return MPARK_DISPATCH_AT(B + 17); case B + 18: return MPARK_DISPATCH_AT(B + 18); case B + 19: return MPARK_DISPATCH_AT(B + 19); case B + 20: return MPARK_DISPATCH_AT(B + 20); case B + 21: return MPARK_DISPATCH_AT(B + 21); case B + 22: return MPARK_DISPATCH_AT(B + 22); case B + 23: return MPARK_DISPATCH_AT(B + 23); case B + 24: return MPARK_DISPATCH_AT(B + 24); case B + 25: return MPARK_DISPATCH_AT(B + 25); case B + 26: return MPARK_DISPATCH_AT(B + 26); case B + 27: return MPARK_DISPATCH_AT(B + 27); case B + 28: return MPARK_DISPATCH_AT(B + 28); case B + 29: return MPARK_DISPATCH_AT(B + 29); case B + 30: return MPARK_DISPATCH_AT(B + 30); case B + 31: return MPARK_DISPATCH_AT(B + 31); default: return MPARK_DEFAULT(B + 32); } #undef MPARK_DEFAULT #undef MPARK_DISPATCH_AT } }; #else template <typename T> inline static constexpr const T &at(const T &elem) noexcept { return elem; } template <typename T, std::size_t N, typename... Is> inline static constexpr const lib::remove_all_extents_t<T> &at( const lib::array<T, N> &elems, std::size_t i, Is... is) noexcept { return at(elems[i], is...); } template <typename F, typename... Fs> inline static constexpr lib::array<lib::decay_t<F>, sizeof...(Fs) + 1> make_farray(F &&f, Fs &&... fs) { return {{lib::forward<F>(f), lib::forward<Fs>(fs)...}}; } template <typename F, typename... Vs> struct make_fmatrix_impl { template <std::size_t... Is> inline static constexpr dispatch_result_t<F, Vs...> dispatch( F &&f, Vs &&... vs) { using Expected = dispatch_result_t<F, Vs...>; using Actual = decltype(lib::invoke( lib::forward<F>(f), access::base::get_alt<Is>(lib::forward<Vs>(vs))...)); return visit_return_type_check<Expected, Actual>::invoke( lib::forward<F>(f), access::base::get_alt<Is>(lib::forward<Vs>(vs))...); } #ifdef MPARK_RETURN_TYPE_DEDUCTION template <std::size_t... Is> inline static constexpr auto impl(lib::index_sequence<Is...>) { return &dispatch<Is...>; } template <typename Is, std::size_t... Js, typename... Ls> inline static constexpr auto impl(Is, lib::index_sequence<Js...>, Ls... ls) { return make_farray(impl(lib::push_back_t<Is, Js>{}, ls...)...); } #else template <typename...> struct impl; template <std::size_t... Is> struct impl<lib::index_sequence<Is...>> { inline constexpr AUTO operator()() const AUTO_RETURN(&dispatch<Is...>) }; template <typename Is, std::size_t... Js, typename... Ls> struct impl<Is, lib::index_sequence<Js...>, Ls...> { inline constexpr AUTO operator()() const AUTO_RETURN( make_farray(impl<lib::push_back_t<Is, Js>, Ls...>{}()...)) }; #endif }; #ifdef MPARK_RETURN_TYPE_DEDUCTION template <typename F, typename... Vs> inline static constexpr auto make_fmatrix() { return make_fmatrix_impl<F, Vs...>::impl( lib::index_sequence<>{}, lib::make_index_sequence<lib::decay_t<Vs>::size()>{}...); } #else template <typename F, typename... Vs> inline static constexpr AUTO make_fmatrix() AUTO_RETURN( typename make_fmatrix_impl<F, Vs...>::template impl< lib::index_sequence<>, lib::make_index_sequence<lib::decay_t<Vs>::size()>...>{}()) #endif template <typename F, typename... Vs> struct make_fdiagonal_impl { template <std::size_t I> inline static constexpr dispatch_result_t<F, Vs...> dispatch( F &&f, Vs &&... vs) { using Expected = dispatch_result_t<F, Vs...>; using Actual = decltype( lib::invoke(lib::forward<F>(f), access::base::get_alt<I>(lib::forward<Vs>(vs))...)); return visit_return_type_check<Expected, Actual>::invoke( lib::forward<F>(f), access::base::get_alt<I>(lib::forward<Vs>(vs))...); } template <std::size_t... Is> inline static constexpr AUTO impl(lib::index_sequence<Is...>) AUTO_RETURN(make_farray(&dispatch<Is>...)) }; template <typename F, typename V, typename... Vs> inline static constexpr auto make_fdiagonal() -> decltype(make_fdiagonal_impl<F, V, Vs...>::impl( lib::make_index_sequence<lib::decay_t<V>::size()>{})) { static_assert(lib::all<(lib::decay_t<V>::size() == lib::decay_t<Vs>::size())...>::value, "all of the variants must be the same size."); return make_fdiagonal_impl<F, V, Vs...>::impl( lib::make_index_sequence<lib::decay_t<V>::size()>{}); } #endif }; #if !defined(MPARK_VARIANT_SWITCH_VISIT) && \ (!defined(_MSC_VER) || _MSC_VER >= 1910) template <typename F, typename... Vs> using fmatrix_t = decltype(base::make_fmatrix<F, Vs...>()); template <typename F, typename... Vs> struct fmatrix { static constexpr fmatrix_t<F, Vs...> value = base::make_fmatrix<F, Vs...>(); }; template <typename F, typename... Vs> constexpr fmatrix_t<F, Vs...> fmatrix<F, Vs...>::value; template <typename F, typename... Vs> using fdiagonal_t = decltype(base::make_fdiagonal<F, Vs...>()); template <typename F, typename... Vs> struct fdiagonal { static constexpr fdiagonal_t<F, Vs...> value = base::make_fdiagonal<F, Vs...>(); }; template <typename F, typename... Vs> constexpr fdiagonal_t<F, Vs...> fdiagonal<F, Vs...>::value; #endif struct alt { template <typename Visitor, typename... Vs> inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, Vs &&... vs) #ifdef MPARK_VARIANT_SWITCH_VISIT DECLTYPE_AUTO_RETURN( base::dispatcher< true, base::dispatch_result_t<Visitor, decltype(as_base( lib::forward<Vs>(vs)))...>>:: template dispatch<0>(lib::forward<Visitor>(visitor), as_base(lib::forward<Vs>(vs))...)) #elif !defined(_MSC_VER) || _MSC_VER >= 1910 DECLTYPE_AUTO_RETURN(base::at( fmatrix<Visitor &&, decltype(as_base(lib::forward<Vs>(vs)))...>::value, vs.index()...)(lib::forward<Visitor>(visitor), as_base(lib::forward<Vs>(vs))...)) #else DECLTYPE_AUTO_RETURN(base::at( base::make_fmatrix<Visitor &&, decltype(as_base(lib::forward<Vs>(vs)))...>(), vs.index()...)(lib::forward<Visitor>(visitor), as_base(lib::forward<Vs>(vs))...)) #endif template <typename Visitor, typename... Vs> inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, Visitor &&visitor, Vs &&... vs) #ifdef MPARK_VARIANT_SWITCH_VISIT DECLTYPE_AUTO_RETURN( base::dispatcher< true, base::dispatch_result_t<Visitor, decltype(as_base( lib::forward<Vs>(vs)))...>>:: template dispatch_at<0>(index, lib::forward<Visitor>(visitor), as_base(lib::forward<Vs>(vs))...)) #elif !defined(_MSC_VER) || _MSC_VER >= 1910 DECLTYPE_AUTO_RETURN(base::at( fdiagonal<Visitor &&, decltype(as_base(lib::forward<Vs>(vs)))...>::value, index)(lib::forward<Visitor>(visitor), as_base(lib::forward<Vs>(vs))...)) #else DECLTYPE_AUTO_RETURN(base::at( base::make_fdiagonal<Visitor &&, decltype(as_base(lib::forward<Vs>(vs)))...>(), index)(lib::forward<Visitor>(visitor), as_base(lib::forward<Vs>(vs))...)) #endif }; struct variant { private: template <typename Visitor> struct visitor { template <typename... Values> inline static constexpr bool does_not_handle() { return lib::is_invocable<Visitor, Values...>::value; } }; template <typename Visitor, typename... Values> struct visit_exhaustiveness_check { static_assert(visitor<Visitor>::template does_not_handle<Values...>(), "`visit` requires the visitor to be exhaustive."); inline static constexpr DECLTYPE_AUTO invoke(Visitor &&visitor, Values &&... values) DECLTYPE_AUTO_RETURN(lib::invoke(lib::forward<Visitor>(visitor), lib::forward<Values>(values)...)) }; template <typename Visitor> struct value_visitor { Visitor &&visitor_; template <typename... Alts> inline constexpr DECLTYPE_AUTO operator()(Alts &&... alts) const DECLTYPE_AUTO_RETURN( visit_exhaustiveness_check< Visitor, decltype((lib::forward<Alts>(alts).value))...>:: invoke(lib::forward<Visitor>(visitor_), lib::forward<Alts>(alts).value...)) }; template <typename Visitor> inline static constexpr AUTO make_value_visitor(Visitor &&visitor) AUTO_RETURN(value_visitor<Visitor>{lib::forward<Visitor>(visitor)}) public: template <typename Visitor, typename... Vs> inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, Vs &&... vs) DECLTYPE_AUTO_RETURN(alt::visit_alt(lib::forward<Visitor>(visitor), lib::forward<Vs>(vs).impl_...)) template <typename Visitor, typename... Vs> inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, Visitor &&visitor, Vs &&... vs) DECLTYPE_AUTO_RETURN( alt::visit_alt_at(index, lib::forward<Visitor>(visitor), lib::forward<Vs>(vs).impl_...)) template <typename Visitor, typename... Vs> inline static constexpr DECLTYPE_AUTO visit_value(Visitor &&visitor, Vs &&... vs) DECLTYPE_AUTO_RETURN( visit_alt(make_value_visitor(lib::forward<Visitor>(visitor)), lib::forward<Vs>(vs)...)) template <typename Visitor, typename... Vs> inline static constexpr DECLTYPE_AUTO visit_value_at(std::size_t index, Visitor &&visitor, Vs &&... vs) DECLTYPE_AUTO_RETURN( visit_alt_at(index, make_value_visitor(lib::forward<Visitor>(visitor)), lib::forward<Vs>(vs)...)) }; } // namespace visitation template <std::size_t Index, typename T> struct alt { using value_type = T; #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4244) #endif template <typename... Args> inline explicit constexpr alt(in_place_t, Args &&... args) : value(lib::forward<Args>(args)...) {} #ifdef _MSC_VER #pragma warning(pop) #endif T value; }; template <Trait DestructibleTrait, std::size_t Index, typename... Ts> union recursive_union; template <Trait DestructibleTrait, std::size_t Index> union recursive_union<DestructibleTrait, Index> {}; #define MPARK_VARIANT_RECURSIVE_UNION(destructible_trait, destructor) \ template <std::size_t Index, typename T, typename... Ts> \ union recursive_union<destructible_trait, Index, T, Ts...> { \ public: \ inline explicit constexpr recursive_union(valueless_t) noexcept \ : dummy_{} {} \ \ template <typename... Args> \ inline explicit constexpr recursive_union(in_place_index_t<0>, \ Args &&... args) \ : head_(in_place_t{}, lib::forward<Args>(args)...) {} \ \ template <std::size_t I, typename... Args> \ inline explicit constexpr recursive_union(in_place_index_t<I>, \ Args &&... args) \ : tail_(in_place_index_t<I - 1>{}, lib::forward<Args>(args)...) {} \ \ recursive_union(const recursive_union &) = default; \ recursive_union(recursive_union &&) = default; \ \ destructor \ \ recursive_union &operator=(const recursive_union &) = default; \ recursive_union &operator=(recursive_union &&) = default; \ \ private: \ char dummy_; \ alt<Index, T> head_; \ recursive_union<destructible_trait, Index + 1, Ts...> tail_; \ \ friend struct access::recursive_union; \ } MPARK_VARIANT_RECURSIVE_UNION(Trait::TriviallyAvailable, ~recursive_union() = default;); MPARK_VARIANT_RECURSIVE_UNION(Trait::Available, ~recursive_union() {}); MPARK_VARIANT_RECURSIVE_UNION(Trait::Unavailable, ~recursive_union() = delete;); #undef MPARK_VARIANT_RECURSIVE_UNION using index_t = unsigned int; template <Trait DestructibleTrait, typename... Ts> class base { public: inline explicit constexpr base(valueless_t tag) noexcept : data_(tag), index_(static_cast<index_t>(-1)) {} template <std::size_t I, typename... Args> inline explicit constexpr base(in_place_index_t<I>, Args &&... args) : data_(in_place_index_t<I>{}, lib::forward<Args>(args)...), index_(I) {} inline constexpr bool valueless_by_exception() const noexcept { return index_ == static_cast<index_t>(-1); } inline constexpr std::size_t index() const noexcept { return valueless_by_exception() ? variant_npos : index_; } protected: using data_t = recursive_union<DestructibleTrait, 0, Ts...>; friend inline constexpr base &as_base(base &b) { return b; } friend inline constexpr const base &as_base(const base &b) { return b; } friend inline constexpr base &&as_base(base &&b) { return lib::move(b); } friend inline constexpr const base &&as_base(const base &&b) { return lib::move(b); } friend inline constexpr data_t &data(base &b) { return b.data_; } friend inline constexpr const data_t &data(const base &b) { return b.data_; } friend inline constexpr data_t &&data(base &&b) { return lib::move(b).data_; } friend inline constexpr const data_t &&data(const base &&b) { return lib::move(b).data_; } inline static constexpr std::size_t size() { return sizeof...(Ts); } data_t data_; index_t index_; friend struct access::base; friend struct visitation::base; }; struct dtor { #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4100) #endif template <typename Alt> inline void operator()(Alt &alt) const noexcept { alt.~Alt(); } #ifdef _MSC_VER #pragma warning(pop) #endif }; #if !defined(_MSC_VER) || _MSC_VER >= 1910 #define MPARK_INHERITING_CTOR(type, base) using base::base; #else #define MPARK_INHERITING_CTOR(type, base) \ template <typename... Args> \ inline explicit constexpr type(Args &&... args) \ : base(lib::forward<Args>(args)...) {} #endif template <typename Traits, Trait = Traits::destructible_trait> class destructor; #define MPARK_VARIANT_DESTRUCTOR(destructible_trait, definition, destroy) \ template <typename... Ts> \ class destructor<traits<Ts...>, destructible_trait> \ : public base<destructible_trait, Ts...> { \ using super = base<destructible_trait, Ts...>; \ \ public: \ MPARK_INHERITING_CTOR(destructor, super) \ using super::operator=; \ \ destructor(const destructor &) = default; \ destructor(destructor &&) = default; \ definition \ destructor &operator=(const destructor &) = default; \ destructor &operator=(destructor &&) = default; \ \ protected: \ destroy \ } MPARK_VARIANT_DESTRUCTOR( Trait::TriviallyAvailable, ~destructor() = default;, inline void destroy() noexcept { this->index_ = static_cast<index_t>(-1); }); MPARK_VARIANT_DESTRUCTOR( Trait::Available, ~destructor() { destroy(); }, inline void destroy() noexcept { if (!this->valueless_by_exception()) { visitation::alt::visit_alt(dtor{}, *this); } this->index_ = static_cast<index_t>(-1); }); MPARK_VARIANT_DESTRUCTOR( Trait::Unavailable, ~destructor() = delete;, inline void destroy() noexcept = delete;); #undef MPARK_VARIANT_DESTRUCTOR template <typename Traits> class constructor : public destructor<Traits> { using super = destructor<Traits>; public: MPARK_INHERITING_CTOR(constructor, super) using super::operator=; protected: #ifndef MPARK_GENERIC_LAMBDAS struct ctor { template <typename LhsAlt, typename RhsAlt> inline void operator()(LhsAlt &lhs_alt, RhsAlt &&rhs_alt) const { constructor::construct_alt(lhs_alt, lib::forward<RhsAlt>(rhs_alt).value); } }; #endif template <std::size_t I, typename T, typename... Args> inline static T &construct_alt(alt<I, T> &a, Args &&... args) { auto *result = ::new (static_cast<void *>(lib::addressof(a))) alt<I, T>(in_place_t{}, lib::forward<Args>(args)...); return result->value; } template <typename Rhs> inline static void generic_construct(constructor &lhs, Rhs &&rhs) { lhs.destroy(); if (!rhs.valueless_by_exception()) { visitation::alt::visit_alt_at( rhs.index(), #ifdef MPARK_GENERIC_LAMBDAS [](auto &lhs_alt, auto &&rhs_alt) { constructor::construct_alt( lhs_alt, lib::forward<decltype(rhs_alt)>(rhs_alt).value); } #else ctor{} #endif , lhs, lib::forward<Rhs>(rhs)); lhs.index_ = rhs.index_; } } }; template <typename Traits, Trait = Traits::move_constructible_trait> class move_constructor; #define MPARK_VARIANT_MOVE_CONSTRUCTOR(move_constructible_trait, definition) \ template <typename... Ts> \ class move_constructor<traits<Ts...>, move_constructible_trait> \ : public constructor<traits<Ts...>> { \ using super = constructor<traits<Ts...>>; \ \ public: \ MPARK_INHERITING_CTOR(move_constructor, super) \ using super::operator=; \ \ move_constructor(const move_constructor &) = default; \ definition \ ~move_constructor() = default; \ move_constructor &operator=(const move_constructor &) = default; \ move_constructor &operator=(move_constructor &&) = default; \ } MPARK_VARIANT_MOVE_CONSTRUCTOR( Trait::TriviallyAvailable, move_constructor(move_constructor &&that) = default;); MPARK_VARIANT_MOVE_CONSTRUCTOR( Trait::Available, move_constructor(move_constructor &&that) noexcept( lib::all<std::is_nothrow_move_constructible<Ts>::value...>::value) : move_constructor(valueless_t{}) { this->generic_construct(*this, lib::move(that)); }); MPARK_VARIANT_MOVE_CONSTRUCTOR( Trait::Unavailable, move_constructor(move_constructor &&) = delete;); #undef MPARK_VARIANT_MOVE_CONSTRUCTOR template <typename Traits, Trait = Traits::copy_constructible_trait> class copy_constructor; #define MPARK_VARIANT_COPY_CONSTRUCTOR(copy_constructible_trait, definition) \ template <typename... Ts> \ class copy_constructor<traits<Ts...>, copy_constructible_trait> \ : public move_constructor<traits<Ts...>> { \ using super = move_constructor<traits<Ts...>>; \ \ public: \ MPARK_INHERITING_CTOR(copy_constructor, super) \ using super::operator=; \ \ definition \ copy_constructor(copy_constructor &&) = default; \ ~copy_constructor() = default; \ copy_constructor &operator=(const copy_constructor &) = default; \ copy_constructor &operator=(copy_constructor &&) = default; \ } MPARK_VARIANT_COPY_CONSTRUCTOR( Trait::TriviallyAvailable, copy_constructor(const copy_constructor &that) = default;); MPARK_VARIANT_COPY_CONSTRUCTOR( Trait::Available, copy_constructor(const copy_constructor &that) : copy_constructor(valueless_t{}) { this->generic_construct(*this, that); }); MPARK_VARIANT_COPY_CONSTRUCTOR( Trait::Unavailable, copy_constructor(const copy_constructor &) = delete;); #undef MPARK_VARIANT_COPY_CONSTRUCTOR template <typename Traits> class assignment : public copy_constructor<Traits> { using super = copy_constructor<Traits>; public: MPARK_INHERITING_CTOR(assignment, super) using super::operator=; template <std::size_t I, typename... Args> inline /* auto & */ auto emplace(Args &&... args) -> decltype(this->construct_alt(access::base::get_alt<I>(*this), lib::forward<Args>(args)...)) { this->destroy(); auto &result = this->construct_alt(access::base::get_alt<I>(*this), lib::forward<Args>(args)...); this->index_ = I; return result; } protected: #ifndef MPARK_GENERIC_LAMBDAS template <typename That> struct assigner { template <typename ThisAlt, typename ThatAlt> inline void operator()(ThisAlt &this_alt, ThatAlt &&that_alt) const { self->assign_alt(this_alt, lib::forward<ThatAlt>(that_alt).value); } assignment *self; }; #endif template <std::size_t I, typename T, typename Arg> inline void assign_alt(alt<I, T> &a, Arg &&arg) { if (this->index() == I) { #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4244) #endif a.value = lib::forward<Arg>(arg); #ifdef _MSC_VER #pragma warning(pop) #endif } else { struct { void operator()(std::true_type) const { this_->emplace<I>(lib::forward<Arg>(arg_)); } void operator()(std::false_type) const { this_->emplace<I>(T(lib::forward<Arg>(arg_))); } assignment *this_; Arg &&arg_; } impl{this, lib::forward<Arg>(arg)}; impl(lib::bool_constant< std::is_nothrow_constructible<T, Arg>::value || !std::is_nothrow_move_constructible<T>::value>{}); } } template <typename That> inline void generic_assign(That &&that) { if (this->valueless_by_exception() && that.valueless_by_exception()) { // do nothing. } else if (that.valueless_by_exception()) { this->destroy(); } else { visitation::alt::visit_alt_at( that.index(), #ifdef MPARK_GENERIC_LAMBDAS [this](auto &this_alt, auto &&that_alt) { this->assign_alt( this_alt, lib::forward<decltype(that_alt)>(that_alt).value); } #else assigner<That>{this} #endif , *this, lib::forward<That>(that)); } } }; template <typename Traits, Trait = Traits::move_assignable_trait> class move_assignment; #define MPARK_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, definition) \ template <typename... Ts> \ class move_assignment<traits<Ts...>, move_assignable_trait> \ : public assignment<traits<Ts...>> { \ using super = assignment<traits<Ts...>>; \ \ public: \ MPARK_INHERITING_CTOR(move_assignment, super) \ using super::operator=; \ \ move_assignment(const move_assignment &) = default; \ move_assignment(move_assignment &&) = default; \ ~move_assignment() = default; \ move_assignment &operator=(const move_assignment &) = default; \ definition \ } MPARK_VARIANT_MOVE_ASSIGNMENT( Trait::TriviallyAvailable, move_assignment &operator=(move_assignment &&that) = default;); MPARK_VARIANT_MOVE_ASSIGNMENT( Trait::Available, move_assignment & operator=(move_assignment &&that) noexcept( lib::all<(std::is_nothrow_move_constructible<Ts>::value && std::is_nothrow_move_assignable<Ts>::value)...>::value) { this->generic_assign(lib::move(that)); return *this; }); MPARK_VARIANT_MOVE_ASSIGNMENT( Trait::Unavailable, move_assignment &operator=(move_assignment &&) = delete;); #undef MPARK_VARIANT_MOVE_ASSIGNMENT template <typename Traits, Trait = Traits::copy_assignable_trait> class copy_assignment; #define MPARK_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, definition) \ template <typename... Ts> \ class copy_assignment<traits<Ts...>, copy_assignable_trait> \ : public move_assignment<traits<Ts...>> { \ using super = move_assignment<traits<Ts...>>; \ \ public: \ MPARK_INHERITING_CTOR(copy_assignment, super) \ using super::operator=; \ \ copy_assignment(const copy_assignment &) = default; \ copy_assignment(copy_assignment &&) = default; \ ~copy_assignment() = default; \ definition \ copy_assignment &operator=(copy_assignment &&) = default; \ } MPARK_VARIANT_COPY_ASSIGNMENT( Trait::TriviallyAvailable, copy_assignment &operator=(const copy_assignment &that) = default;); MPARK_VARIANT_COPY_ASSIGNMENT( Trait::Available, copy_assignment &operator=(const copy_assignment &that) { this->generic_assign(that); return *this; }); MPARK_VARIANT_COPY_ASSIGNMENT( Trait::Unavailable, copy_assignment &operator=(const copy_assignment &) = delete;); #undef MPARK_VARIANT_COPY_ASSIGNMENT template <typename... Ts> class impl : public copy_assignment<traits<Ts...>> { using super = copy_assignment<traits<Ts...>>; public: MPARK_INHERITING_CTOR(impl, super) using super::operator=; impl(const impl&) = default; impl(impl&&) = default; ~impl() = default; impl &operator=(const impl &) = default; impl &operator=(impl &&) = default; template <std::size_t I, typename Arg> inline void assign(Arg &&arg) { this->assign_alt(access::base::get_alt<I>(*this), lib::forward<Arg>(arg)); } inline void swap(impl &that) { if (this->valueless_by_exception() && that.valueless_by_exception()) { // do nothing. } else if (this->index() == that.index()) { visitation::alt::visit_alt_at(this->index(), #ifdef MPARK_GENERIC_LAMBDAS [](auto &this_alt, auto &that_alt) { using std::swap; swap(this_alt.value, that_alt.value); } #else swapper{} #endif , *this, that); } else { impl *lhs = this; impl *rhs = lib::addressof(that); if (lhs->move_nothrow() && !rhs->move_nothrow()) { std::swap(lhs, rhs); } impl tmp(lib::move(*rhs)); #ifdef MPARK_EXCEPTIONS // EXTENSION: When the move construction of `lhs` into `rhs` throws // and `tmp` is nothrow move constructible then we move `tmp` back // into `rhs` and provide the strong exception safety guarantee. try { this->generic_construct(*rhs, lib::move(*lhs)); } catch (...) { if (tmp.move_nothrow()) { this->generic_construct(*rhs, lib::move(tmp)); } throw; } #else this->generic_construct(*rhs, lib::move(*lhs)); #endif this->generic_construct(*lhs, lib::move(tmp)); } } private: #ifndef MPARK_GENERIC_LAMBDAS struct swapper { template <typename ThisAlt, typename ThatAlt> inline void operator()(ThisAlt &this_alt, ThatAlt &that_alt) const { using std::swap; swap(this_alt.value, that_alt.value); } }; #endif inline constexpr bool move_nothrow() const { return this->valueless_by_exception() || lib::array<bool, sizeof...(Ts)>{ {std::is_nothrow_move_constructible<Ts>::value...} }[this->index()]; } }; #undef MPARK_INHERITING_CTOR template <std::size_t I, typename T> struct overload_leaf { using F = lib::size_constant<I> (*)(T); operator F() const { return nullptr; } }; template <typename... Ts> struct overload_impl { private: template <typename> struct impl; template <std::size_t... Is> struct impl<lib::index_sequence<Is...>> : overload_leaf<Is, Ts>... {}; public: using type = impl<lib::index_sequence_for<Ts...>>; }; template <typename... Ts> using overload = typename overload_impl<Ts...>::type; template <typename T, typename... Ts> using best_match = lib::invoke_result_t<overload<Ts...>, T &&>; template <typename T> struct is_in_place_index : std::false_type {}; template <std::size_t I> struct is_in_place_index<in_place_index_t<I>> : std::true_type {}; template <typename T> struct is_in_place_type : std::false_type {}; template <typename T> struct is_in_place_type<in_place_type_t<T>> : std::true_type {}; } // detail template <typename... Ts> class variant { static_assert(0 < sizeof...(Ts), "variant must consist of at least one alternative."); static_assert(lib::all<!std::is_array<Ts>::value...>::value, "variant can not have an array type as an alternative."); static_assert(lib::all<!std::is_reference<Ts>::value...>::value, "variant can not have a reference type as an alternative."); static_assert(lib::all<!std::is_void<Ts>::value...>::value, "variant can not have a void type as an alternative."); public: template < typename Front = lib::type_pack_element_t<0, Ts...>, lib::enable_if_t<std::is_default_constructible<Front>::value, int> = 0> inline constexpr variant() noexcept( std::is_nothrow_default_constructible<Front>::value) : impl_(in_place_index_t<0>{}) {} variant(const variant &) = default; variant(variant &&) = default; template < typename Arg, typename Decayed = lib::decay_t<Arg>, lib::enable_if_t<!std::is_same<Decayed, variant>::value, int> = 0, lib::enable_if_t<!detail::is_in_place_index<Decayed>::value, int> = 0, lib::enable_if_t<!detail::is_in_place_type<Decayed>::value, int> = 0, std::size_t I = detail::best_match<Arg, Ts...>::value, typename T = lib::type_pack_element_t<I, Ts...>, lib::enable_if_t<std::is_constructible<T, Arg>::value, int> = 0> inline constexpr variant(Arg &&arg) noexcept( std::is_nothrow_constructible<T, Arg>::value) : impl_(in_place_index_t<I>{}, lib::forward<Arg>(arg)) {} template < std::size_t I, typename... Args, typename T = lib::type_pack_element_t<I, Ts...>, lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> inline explicit constexpr variant( in_place_index_t<I>, Args &&... args) noexcept(std::is_nothrow_constructible<T, Args...>::value) : impl_(in_place_index_t<I>{}, lib::forward<Args>(args)...) {} template < std::size_t I, typename Up, typename... Args, typename T = lib::type_pack_element_t<I, Ts...>, lib::enable_if_t<std::is_constructible<T, std::initializer_list<Up> &, Args...>::value, int> = 0> inline explicit constexpr variant( in_place_index_t<I>, std::initializer_list<Up> il, Args &&... args) noexcept(std:: is_nothrow_constructible< T, std::initializer_list<Up> &, Args...>::value) : impl_(in_place_index_t<I>{}, il, lib::forward<Args>(args)...) {} template < typename T, typename... Args, std::size_t I = detail::find_index_sfinae<T, Ts...>::value, lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> inline explicit constexpr variant( in_place_type_t<T>, Args &&... args) noexcept(std::is_nothrow_constructible<T, Args...>::value) : impl_(in_place_index_t<I>{}, lib::forward<Args>(args)...) {} template < typename T, typename Up, typename... Args, std::size_t I = detail::find_index_sfinae<T, Ts...>::value, lib::enable_if_t<std::is_constructible<T, std::initializer_list<Up> &, Args...>::value, int> = 0> inline explicit constexpr variant( in_place_type_t<T>, std::initializer_list<Up> il, Args &&... args) noexcept(std:: is_nothrow_constructible< T, std::initializer_list<Up> &, Args...>::value) : impl_(in_place_index_t<I>{}, il, lib::forward<Args>(args)...) {} ~variant() = default; variant &operator=(const variant &) = default; variant &operator=(variant &&) = default; template <typename Arg, lib::enable_if_t<!std::is_same<lib::decay_t<Arg>, variant>::value, int> = 0, std::size_t I = detail::best_match<Arg, Ts...>::value, typename T = lib::type_pack_element_t<I, Ts...>, lib::enable_if_t<(std::is_assignable<T &, Arg>::value && std::is_constructible<T, Arg>::value), int> = 0> inline variant &operator=(Arg &&arg) noexcept( (std::is_nothrow_assignable<T &, Arg>::value && std::is_nothrow_constructible<T, Arg>::value)) { impl_.template assign<I>(lib::forward<Arg>(arg)); return *this; } template < std::size_t I, typename... Args, typename T = lib::type_pack_element_t<I, Ts...>, lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> inline T &emplace(Args &&... args) { return impl_.template emplace<I>(lib::forward<Args>(args)...); } template < std::size_t I, typename Up, typename... Args, typename T = lib::type_pack_element_t<I, Ts...>, lib::enable_if_t<std::is_constructible<T, std::initializer_list<Up> &, Args...>::value, int> = 0> inline T &emplace(std::initializer_list<Up> il, Args &&... args) { return impl_.template emplace<I>(il, lib::forward<Args>(args)...); } template < typename T, typename... Args, std::size_t I = detail::find_index_sfinae<T, Ts...>::value, lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> inline T &emplace(Args &&... args) { return impl_.template emplace<I>(lib::forward<Args>(args)...); } template < typename T, typename Up, typename... Args, std::size_t I = detail::find_index_sfinae<T, Ts...>::value, lib::enable_if_t<std::is_constructible<T, std::initializer_list<Up> &, Args...>::value, int> = 0> inline T &emplace(std::initializer_list<Up> il, Args &&... args) { return impl_.template emplace<I>(il, lib::forward<Args>(args)...); } inline constexpr bool valueless_by_exception() const noexcept { return impl_.valueless_by_exception(); } inline constexpr std::size_t index() const noexcept { return impl_.index(); } template <bool Dummy = true, lib::enable_if_t< lib::all<Dummy, (lib::dependent_type<std::is_move_constructible<Ts>, Dummy>::value && lib::dependent_type<lib::is_swappable<Ts>, Dummy>::value)...>::value, int> = 0> inline void swap(variant &that) noexcept( lib::all<(std::is_nothrow_move_constructible<Ts>::value && lib::is_nothrow_swappable<Ts>::value)...>::value) { impl_.swap(that.impl_); } private: detail::impl<Ts...> impl_; friend struct detail::access::variant; friend struct detail::visitation::variant; }; template <std::size_t I, typename... Ts> inline constexpr bool holds_alternative(const variant<Ts...> &v) noexcept { return v.index() == I; } template <typename T, typename... Ts> inline constexpr bool holds_alternative(const variant<Ts...> &v) noexcept { return holds_alternative<detail::find_index_checked<T, Ts...>::value>(v); } namespace detail { template <std::size_t I, typename V> struct generic_get_impl { constexpr generic_get_impl(int) noexcept {} constexpr AUTO_REFREF operator()(V &&v) const AUTO_REFREF_RETURN( access::variant::get_alt<I>(lib::forward<V>(v)).value) }; template <std::size_t I, typename V> inline constexpr AUTO_REFREF generic_get(V &&v) AUTO_REFREF_RETURN(generic_get_impl<I, V>( holds_alternative<I>(v) ? 0 : (throw_bad_variant_access(), 0))( lib::forward<V>(v))) } // namespace detail template <std::size_t I, typename... Ts> inline constexpr variant_alternative_t<I, variant<Ts...>> &get( variant<Ts...> &v) { return detail::generic_get<I>(v); } template <std::size_t I, typename... Ts> inline constexpr variant_alternative_t<I, variant<Ts...>> &&get( variant<Ts...> &&v) { return detail::generic_get<I>(lib::move(v)); } template <std::size_t I, typename... Ts> inline constexpr const variant_alternative_t<I, variant<Ts...>> &get( const variant<Ts...> &v) { return detail::generic_get<I>(v); } template <std::size_t I, typename... Ts> inline constexpr const variant_alternative_t<I, variant<Ts...>> &&get( const variant<Ts...> &&v) { return detail::generic_get<I>(lib::move(v)); } template <typename T, typename... Ts> inline constexpr T &get(variant<Ts...> &v) { return get<detail::find_index_checked<T, Ts...>::value>(v); } template <typename T, typename... Ts> inline constexpr T &&get(variant<Ts...> &&v) { return get<detail::find_index_checked<T, Ts...>::value>(lib::move(v)); } template <typename T, typename... Ts> inline constexpr const T &get(const variant<Ts...> &v) { return get<detail::find_index_checked<T, Ts...>::value>(v); } template <typename T, typename... Ts> inline constexpr const T &&get(const variant<Ts...> &&v) { return get<detail::find_index_checked<T, Ts...>::value>(lib::move(v)); } namespace detail { template <std::size_t I, typename V> inline constexpr /* auto * */ AUTO generic_get_if(V *v) noexcept AUTO_RETURN(v && holds_alternative<I>(*v) ? lib::addressof(access::variant::get_alt<I>(*v).value) : nullptr) } // namespace detail template <std::size_t I, typename... Ts> inline constexpr lib::add_pointer_t<variant_alternative_t<I, variant<Ts...>>> get_if(variant<Ts...> *v) noexcept { return detail::generic_get_if<I>(v); } template <std::size_t I, typename... Ts> inline constexpr lib::add_pointer_t< const variant_alternative_t<I, variant<Ts...>>> get_if(const variant<Ts...> *v) noexcept { return detail::generic_get_if<I>(v); } template <typename T, typename... Ts> inline constexpr lib::add_pointer_t<T> get_if(variant<Ts...> *v) noexcept { return get_if<detail::find_index_checked<T, Ts...>::value>(v); } template <typename T, typename... Ts> inline constexpr lib::add_pointer_t<const T> get_if(const variant<Ts...> *v) noexcept { return get_if<detail::find_index_checked<T, Ts...>::value>(v); } namespace detail { template <typename RelOp> struct convert_to_bool { template <typename Lhs, typename Rhs> inline constexpr bool operator()(Lhs &&lhs, Rhs &&rhs) const { static_assert(std::is_convertible<lib::invoke_result_t<RelOp, Lhs, Rhs>, bool>::value, "relational operators must return a type" " implicitly convertible to bool"); return lib::invoke( RelOp{}, lib::forward<Lhs>(lhs), lib::forward<Rhs>(rhs)); } }; } // namespace detail template <typename... Ts> inline constexpr bool operator==(const variant<Ts...> &lhs, const variant<Ts...> &rhs) { using detail::visitation::variant; using equal_to = detail::convert_to_bool<lib::equal_to>; #ifdef MPARK_CPP14_CONSTEXPR if (lhs.index() != rhs.index()) return false; if (lhs.valueless_by_exception()) return true; return variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs); #else return lhs.index() == rhs.index() && (lhs.valueless_by_exception() || variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs)); #endif } template <typename... Ts> inline constexpr bool operator!=(const variant<Ts...> &lhs, const variant<Ts...> &rhs) { using detail::visitation::variant; using not_equal_to = detail::convert_to_bool<lib::not_equal_to>; #ifdef MPARK_CPP14_CONSTEXPR if (lhs.index() != rhs.index()) return true; if (lhs.valueless_by_exception()) return false; return variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs); #else return lhs.index() != rhs.index() || (!lhs.valueless_by_exception() && variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs)); #endif } template <typename... Ts> inline constexpr bool operator<(const variant<Ts...> &lhs, const variant<Ts...> &rhs) { using detail::visitation::variant; using less = detail::convert_to_bool<lib::less>; #ifdef MPARK_CPP14_CONSTEXPR if (rhs.valueless_by_exception()) return false; if (lhs.valueless_by_exception()) return true; if (lhs.index() < rhs.index()) return true; if (lhs.index() > rhs.index()) return false; return variant::visit_value_at(lhs.index(), less{}, lhs, rhs); #else return !rhs.valueless_by_exception() && (lhs.valueless_by_exception() || lhs.index() < rhs.index() || (lhs.index() == rhs.index() && variant::visit_value_at(lhs.index(), less{}, lhs, rhs))); #endif } template <typename... Ts> inline constexpr bool operator>(const variant<Ts...> &lhs, const variant<Ts...> &rhs) { using detail::visitation::variant; using greater = detail::convert_to_bool<lib::greater>; #ifdef MPARK_CPP14_CONSTEXPR if (lhs.valueless_by_exception()) return false; if (rhs.valueless_by_exception()) return true; if (lhs.index() > rhs.index()) return true; if (lhs.index() < rhs.index()) return false; return variant::visit_value_at(lhs.index(), greater{}, lhs, rhs); #else return !lhs.valueless_by_exception() && (rhs.valueless_by_exception() || lhs.index() > rhs.index() || (lhs.index() == rhs.index() && variant::visit_value_at(lhs.index(), greater{}, lhs, rhs))); #endif } template <typename... Ts> inline constexpr bool operator<=(const variant<Ts...> &lhs, const variant<Ts...> &rhs) { using detail::visitation::variant; using less_equal = detail::convert_to_bool<lib::less_equal>; #ifdef MPARK_CPP14_CONSTEXPR if (lhs.valueless_by_exception()) return true; if (rhs.valueless_by_exception()) return false; if (lhs.index() < rhs.index()) return true; if (lhs.index() > rhs.index()) return false; return variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs); #else return lhs.valueless_by_exception() || (!rhs.valueless_by_exception() && (lhs.index() < rhs.index() || (lhs.index() == rhs.index() && variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs)))); #endif } template <typename... Ts> inline constexpr bool operator>=(const variant<Ts...> &lhs, const variant<Ts...> &rhs) { using detail::visitation::variant; using greater_equal = detail::convert_to_bool<lib::greater_equal>; #ifdef MPARK_CPP14_CONSTEXPR if (rhs.valueless_by_exception()) return true; if (lhs.valueless_by_exception()) return false; if (lhs.index() > rhs.index()) return true; if (lhs.index() < rhs.index()) return false; return variant::visit_value_at(lhs.index(), greater_equal{}, lhs, rhs); #else return rhs.valueless_by_exception() || (!lhs.valueless_by_exception() && (lhs.index() > rhs.index() || (lhs.index() == rhs.index() && variant::visit_value_at( lhs.index(), greater_equal{}, lhs, rhs)))); #endif } struct monostate {}; inline constexpr bool operator<(monostate, monostate) noexcept { return false; } inline constexpr bool operator>(monostate, monostate) noexcept { return false; } inline constexpr bool operator<=(monostate, monostate) noexcept { return true; } inline constexpr bool operator>=(monostate, monostate) noexcept { return true; } inline constexpr bool operator==(monostate, monostate) noexcept { return true; } inline constexpr bool operator!=(monostate, monostate) noexcept { return false; } #ifdef MPARK_CPP14_CONSTEXPR namespace detail { inline constexpr bool all(std::initializer_list<bool> bs) { for (bool b : bs) { if (!b) { return false; } } return true; } } // namespace detail template <typename Visitor, typename... Vs> inline constexpr decltype(auto) visit(Visitor &&visitor, Vs &&... vs) { return (detail::all({!vs.valueless_by_exception()...}) ? (void)0 : throw_bad_variant_access()), detail::visitation::variant::visit_value( lib::forward<Visitor>(visitor), lib::forward<Vs>(vs)...); } #else namespace detail { template <std::size_t N> inline constexpr bool all_impl(const lib::array<bool, N> &bs, std::size_t idx) { return idx >= N || (bs[idx] && all_impl(bs, idx + 1)); } template <std::size_t N> inline constexpr bool all(const lib::array<bool, N> &bs) { return all_impl(bs, 0); } } // namespace detail template <typename Visitor, typename... Vs> inline constexpr DECLTYPE_AUTO visit(Visitor &&visitor, Vs &&... vs) DECLTYPE_AUTO_RETURN( (detail::all( lib::array<bool, sizeof...(Vs)>{{!vs.valueless_by_exception()...}}) ? (void)0 : throw_bad_variant_access()), detail::visitation::variant::visit_value(lib::forward<Visitor>(visitor), lib::forward<Vs>(vs)...)) #endif template <typename... Ts> inline auto swap(variant<Ts...> &lhs, variant<Ts...> &rhs) noexcept(noexcept(lhs.swap(rhs))) -> decltype(lhs.swap(rhs)) { lhs.swap(rhs); } namespace detail { template <typename T, typename...> using enabled_type = T; namespace hash { template <typename H, typename K> constexpr bool meets_requirements() noexcept { return std::is_copy_constructible<H>::value && std::is_move_constructible<H>::value && lib::is_invocable_r<std::size_t, H, const K &>::value; } template <typename K> constexpr bool is_enabled() noexcept { using H = std::hash<K>; return meets_requirements<H, K>() && std::is_default_constructible<H>::value && std::is_copy_assignable<H>::value && std::is_move_assignable<H>::value; } } // namespace hash } // namespace detail #undef AUTO #undef AUTO_RETURN #undef AUTO_REFREF #undef AUTO_REFREF_RETURN #undef DECLTYPE_AUTO #undef DECLTYPE_AUTO_RETURN } // namespace mpark namespace std { template <typename... Ts> struct hash<mpark::detail::enabled_type< mpark::variant<Ts...>, mpark::lib::enable_if_t<mpark::lib::all<mpark::detail::hash::is_enabled< mpark::lib::remove_const_t<Ts>>()...>::value>>> { using argument_type = mpark::variant<Ts...>; using result_type = std::size_t; inline result_type operator()(const argument_type &v) const { using mpark::detail::visitation::variant; std::size_t result = v.valueless_by_exception() ? 299792458 // Random value chosen by the universe upon creation : variant::visit_alt( #ifdef MPARK_GENERIC_LAMBDAS [](const auto &alt) { using alt_type = mpark::lib::decay_t<decltype(alt)>; using value_type = mpark::lib::remove_const_t< typename alt_type::value_type>; return hash<value_type>{}(alt.value); } #else hasher{} #endif , v); return hash_combine(result, hash<std::size_t>{}(v.index())); } private: #ifndef MPARK_GENERIC_LAMBDAS struct hasher { template <typename Alt> inline std::size_t operator()(const Alt &alt) const { using alt_type = mpark::lib::decay_t<Alt>; using value_type = mpark::lib::remove_const_t<typename alt_type::value_type>; return hash<value_type>{}(alt.value); } }; #endif static std::size_t hash_combine(std::size_t lhs, std::size_t rhs) { return lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2); } }; template <> struct hash<mpark::monostate> { using argument_type = mpark::monostate; using result_type = std::size_t; inline result_type operator()(const argument_type &) const noexcept { return 66740831; // return a fundamentally attractive random value. } }; } // namespace std #endif // MPARK_VARIANT_HPP