diff options
Diffstat (limited to 'source/core/StarVariant.hpp')
-rw-r--r-- | source/core/StarVariant.hpp | 927 |
1 files changed, 927 insertions, 0 deletions
diff --git a/source/core/StarVariant.hpp b/source/core/StarVariant.hpp new file mode 100644 index 0000000..fe45a6d --- /dev/null +++ b/source/core/StarVariant.hpp @@ -0,0 +1,927 @@ +#ifndef STAR_VARIANT_HPP +#define STAR_VARIANT_HPP + +#include <type_traits> +#include <utility> + +#include "StarAlgorithm.hpp" +#include "StarMaybe.hpp" + +namespace Star { + +STAR_EXCEPTION(BadVariantCast, StarException); +STAR_EXCEPTION(BadVariantType, StarException); + +typedef uint8_t VariantTypeIndex; +VariantTypeIndex const InvalidVariantType = 255; + +namespace detail { + template <typename T, typename... Args> + struct HasType; + + template <typename T> + struct HasType<T> : std::false_type {}; + + template <typename T, typename Head, typename... Args> + struct HasType<T, Head, Args...> { + static constexpr bool value = std::is_same<T, Head>::value || HasType<T, Args...>::value; + }; + + template <typename... Args> + struct IsNothrowMoveConstructible; + + template <> + struct IsNothrowMoveConstructible<> : std::true_type {}; + + template <typename Head, typename... Args> + struct IsNothrowMoveConstructible<Head, Args...> { + static constexpr bool value = std::is_nothrow_move_constructible<Head>::value && IsNothrowMoveConstructible<Args...>::value; + }; + + template <typename... Args> + struct IsNothrowMoveAssignable; + + template <> + struct IsNothrowMoveAssignable<> : std::true_type {}; + + template <typename Head, typename... Args> + struct IsNothrowMoveAssignable<Head, Args...> { + static constexpr bool value = std::is_nothrow_move_assignable<Head>::value && IsNothrowMoveAssignable<Args...>::value; + }; +} + +// Stack based variant type container that can be inhabited by one of a limited +// number of types. +template <typename FirstType, typename... RestTypes> +class Variant { +public: + template <typename T> + using ValidateType = typename std::enable_if<detail::HasType<T, FirstType, RestTypes...>::value, void>::type; + + template <typename T, typename = ValidateType<T>> + static constexpr VariantTypeIndex typeIndexOf(); + + // If the first type has a default constructor, constructs an Variant which + // contains a default constructed value of that type. + Variant(); + + template <typename T, typename = ValidateType<T>> + Variant(T const& x); + template <typename T, typename = ValidateType<T>> + Variant(T&& x); + + Variant(Variant const& x); + Variant(Variant&& x) noexcept(detail::IsNothrowMoveConstructible<FirstType, RestTypes...>::value); + + ~Variant(); + + // Implementations of operator= may invalidate the Variant if the copy or + // move constructor of the assigned value throws. + Variant& operator=(Variant const& x); + Variant& operator=(Variant&& x) noexcept(detail::IsNothrowMoveAssignable<FirstType, RestTypes...>::value); + template <typename T, typename = ValidateType<T>> + Variant& operator=(T const& x); + template <typename T, typename = ValidateType<T>> + Variant& operator=(T&& x); + + // Returns true if this Variant contains the given type. + template <typename T, typename = ValidateType<T>> + bool is() const; + + // get throws BadVariantCast on bad casts + + template <typename T, typename = ValidateType<T>> + T const& get() const; + + template <typename T, typename = ValidateType<T>> + T& get(); + + template <typename T, typename = ValidateType<T>> + Maybe<T> maybe() const; + + // ptr() does not throw if this Variant does not hold the given type, instead + // simply returns nullptr. + + template <typename T, typename = ValidateType<T>> + T const* ptr() const; + + template <typename T, typename = ValidateType<T>> + T* ptr(); + + // Calls the given function with the type currently being held, and returns + // the value returned by that function. Will throw if this Variant has been + // invalidated. + template <typename Function> + decltype(auto) call(Function&& function); + template <typename Function> + decltype(auto) call(Function&& function) const; + + // Returns an index for the held type, which can be passed into makeType to + // make this Variant hold a specific type. Returns InvalidVariantType if + // invalidated. + VariantTypeIndex typeIndex() const; + + // Make this Variant hold a new default constructed type of the given type + // index. Can only be used if every alternative type has a default + // constructor. Throws if given an out of range type index or + // InvalidVariantType. + void makeType(VariantTypeIndex typeIndex); + + // True if this Variant has been invalidated. If the copy or move + // constructor of a type throws an exception during assignment, there is no + // *good* way to ensure that the Variant has a valid type, so it may become + // invalidated. It is not possible to directly construct an invalidated + // Variant. + bool invalid() const; + + // Requires that every type included in this Variant has operator== + bool operator==(Variant const& x) const; + bool operator!=(Variant const& x) const; + + // Requires that every type included in this Variant has operator< + bool operator<(Variant const& x) const; + + template <typename T, typename = ValidateType<T>> + bool operator==(T const& x) const; + template <typename T, typename = ValidateType<T>> + bool operator!=(T const& x) const; + template <typename T, typename = ValidateType<T>> + bool operator<(T const& x) const; + +private: + template <typename MatchType, VariantTypeIndex Index, typename... Rest> + struct LookupTypeIndex; + + template <typename MatchType, VariantTypeIndex Index> + struct LookupTypeIndex<MatchType, Index> { + static VariantTypeIndex const value = InvalidVariantType; + }; + + template <typename MatchType, VariantTypeIndex Index, typename Head, typename... Rest> + struct LookupTypeIndex<MatchType, Index, Head, Rest...> { + static VariantTypeIndex const value = std::is_same<MatchType, Head>::value ? Index : LookupTypeIndex<MatchType, Index + 1, Rest...>::value; + }; + + template <typename MatchType> + struct TypeIndex { + static VariantTypeIndex const value = LookupTypeIndex<MatchType, 0, FirstType, RestTypes...>::value; + }; + + void destruct(); + + template <typename T> + void assign(T&& x); + + template <typename Function, typename T> + decltype(auto) doCall(Function&& function); + template <typename Function, typename T1, typename T2, typename... TL> + decltype(auto) doCall(Function&& function); + + template <typename Function, typename T> + decltype(auto) doCall(Function&& function) const; + template <typename Function, typename T1, typename T2, typename... TL> + decltype(auto) doCall(Function&& function) const; + + template <typename First> + void doMakeType(VariantTypeIndex); + template <typename First, typename Second, typename... Rest> + void doMakeType(VariantTypeIndex typeIndex); + + typename std::aligned_union<0, FirstType, RestTypes...>::type m_buffer; + VariantTypeIndex m_typeIndex = InvalidVariantType; +}; + +// A version of Variant that has always has a default "empty" state, useful +// when there is no good default type for a Variant but it needs to be default +// constructed, and is slightly more convenient than Maybe<Variant<Types...>>. +template <typename... Types> +class MVariant { +public: + template <typename T> + using ValidateType = typename std::enable_if<detail::HasType<T, Types...>::value, void>::type; + + template <typename T, typename = ValidateType<T>> + static constexpr VariantTypeIndex typeIndexOf(); + + MVariant(); + MVariant(MVariant const& x); + MVariant(MVariant&& x); + + template <typename T, typename = ValidateType<T>> + MVariant(T const& x); + template <typename T, typename = ValidateType<T>> + MVariant(T&& x); + + MVariant(Variant<Types...> const& x); + MVariant(Variant<Types...>&& x); + + ~MVariant(); + + // MVariant::operator= will never invalidate the MVariant, instead it will + // just become empty. + MVariant& operator=(MVariant const& x); + MVariant& operator=(MVariant&& x); + + template <typename T, typename = ValidateType<T>> + MVariant& operator=(T const& x); + template <typename T, typename = ValidateType<T>> + MVariant& operator=(T&& x); + + MVariant& operator=(Variant<Types...> const& x); + MVariant& operator=(Variant<Types...>&& x); + + // Requires that every type included in this MVariant has operator== + bool operator==(MVariant const& x) const; + bool operator!=(MVariant const& x) const; + + // Requires that every type included in this MVariant has operator< + bool operator<(MVariant const& x) const; + + template <typename T, typename = ValidateType<T>> + bool operator==(T const& x) const; + template <typename T, typename = ValidateType<T>> + bool operator!=(T const& x) const; + template <typename T, typename = ValidateType<T>> + bool operator<(T const& x) const; + + // get throws BadVariantCast on bad casts + + template <typename T, typename = ValidateType<T>> + T const& get() const; + + template <typename T, typename = ValidateType<T>> + T& get(); + + // maybe() and ptr() do not throw if this MVariant does not hold the given + // type, instead simply returns Nothing / nullptr. + + template <typename T, typename = ValidateType<T>> + Maybe<T> maybe() const; + + template <typename T, typename = ValidateType<T>> + T const* ptr() const; + + template <typename T, typename = ValidateType<T>> + T* ptr(); + + template <typename T, typename = ValidateType<T>> + bool is() const; + + // Takes the given value out and leaves this empty + template <typename T, typename = ValidateType<T>> + T take(); + + // Returns a Variant of all the allowed types if non-empty, throws + // BadVariantCast if empty. + Variant<Types...> value() const; + + // Moves the contents of this MVariant into the given Variant if non-empty, + // throws BadVariantCast if empty. + Variant<Types...> takeValue(); + + bool empty() const; + void reset(); + + // Equivalent to !empty() + explicit operator bool() const; + + // If this MVariant holds a type, calls the given function with the type + // being held. If nothing is currently held, the function is not called. + template <typename Function> + void call(Function&& function); + + template <typename Function> + void call(Function&& function) const; + + // Returns an index for the held type, which can be passed into makeType to + // make this MVariant hold a specific type. Types are always indexed in the + // order they are specified starting from 1. A type index of 0 indicates an + // empty MVariant. + VariantTypeIndex typeIndex() const; + + // Make this MVariant hold a new default constructed type of the given type + // index. Can only be used if every alternative type has a default + // constructor. + void makeType(VariantTypeIndex typeIndex); + +private: + struct MVariantEmpty { + bool operator==(MVariantEmpty const& rhs) const; + bool operator<(MVariantEmpty const& rhs) const; + }; + + template <typename Function> + struct RefCaller { + Function&& function; + + RefCaller(Function&& function); + + void operator()(MVariantEmpty& empty); + + template <typename T> + void operator()(T& t); + }; + + template <typename Function> + struct ConstRefCaller { + Function&& function; + + ConstRefCaller(Function&& function); + + void operator()(MVariantEmpty const& empty); + + template <typename T> + void operator()(T const& t); + }; + + Variant<MVariantEmpty, Types...> m_variant; +}; + +template <typename FirstType, typename... RestTypes> +template <typename T, typename> +constexpr VariantTypeIndex Variant<FirstType, RestTypes...>::typeIndexOf() { + return TypeIndex<T>::value; +} + +template <typename FirstType, typename... RestTypes> +Variant<FirstType, RestTypes...>::Variant() + : Variant(FirstType()) {} + +template <typename FirstType, typename... RestTypes> +template <typename T, typename> +Variant<FirstType, RestTypes...>::Variant(T const& x) { + assign(x); +} + +template <typename FirstType, typename... RestTypes> +template <typename T, typename> +Variant<FirstType, RestTypes...>::Variant(T&& x) { + assign(forward<T>(x)); +} + +template <typename FirstType, typename... RestTypes> +Variant<FirstType, RestTypes...>::Variant(Variant const& x) { + x.call([this](auto const& t) { + assign(t); + }); +} + +template <typename FirstType, typename... RestTypes> +Variant<FirstType, RestTypes...>::Variant(Variant&& x) + noexcept(detail::IsNothrowMoveConstructible<FirstType, RestTypes...>::value) { + x.call([this](auto& t) { + assign(move(t)); + }); +} + +template <typename FirstType, typename... RestTypes> +Variant<FirstType, RestTypes...>::~Variant() { + destruct(); +} + +template <typename FirstType, typename... RestTypes> +Variant<FirstType, RestTypes...>& Variant<FirstType, RestTypes...>::operator=(Variant const& x) { + if (&x == this) + return *this; + + x.call([this](auto const& t) { + assign(t); + }); + + return *this; +} + +template <typename FirstType, typename... RestTypes> +Variant<FirstType, RestTypes...>& Variant<FirstType, RestTypes...>::operator=(Variant&& x) + noexcept(detail::IsNothrowMoveAssignable<FirstType, RestTypes...>::value) { + if (&x == this) + return *this; + + x.call([this](auto& t) { + assign(move(t)); + }); + + return *this; +} + +template <typename FirstType, typename... RestTypes> +template <typename T, typename> +Variant<FirstType, RestTypes...>& Variant<FirstType, RestTypes...>::operator=(T const& x) { + assign(x); + return *this; +} + +template <typename FirstType, typename... RestTypes> +template <typename T, typename> +Variant<FirstType, RestTypes...>& Variant<FirstType, RestTypes...>::operator=(T&& x) { + assign(forward<T>(x)); + return *this; +} + +template <typename FirstType, typename... RestTypes> +template <typename T, typename> +T const& Variant<FirstType, RestTypes...>::get() const { + if (!is<T>()) + throw BadVariantCast(); + return *(T*)(&m_buffer); +} + +template <typename FirstType, typename... RestTypes> +template <typename T, typename> +T& Variant<FirstType, RestTypes...>::get() { + if (!is<T>()) + throw BadVariantCast(); + return *(T*)(&m_buffer); +} + +template <typename FirstType, typename... RestTypes> +template <typename T, typename> +Maybe<T> Variant<FirstType, RestTypes...>::maybe() const { + if (!is<T>()) + return {}; + return *(T*)(&m_buffer); +} + +template <typename FirstType, typename... RestTypes> +template <typename T, typename> +T const* Variant<FirstType, RestTypes...>::ptr() const { + if (!is<T>()) + return nullptr; + return (T*)(&m_buffer); +} + +template <typename FirstType, typename... RestTypes> +template <typename T, typename> +T* Variant<FirstType, RestTypes...>::ptr() { + if (!is<T>()) + return nullptr; + return (T*)(&m_buffer); +} + +template <typename FirstType, typename... RestTypes> +template <typename T, typename> +bool Variant<FirstType, RestTypes...>::is() const { + return m_typeIndex == TypeIndex<T>::value; +} + +template <typename FirstType, typename... RestTypes> +template <typename Function> +decltype(auto) Variant<FirstType, RestTypes...>::call(Function&& function) { + return doCall<Function, FirstType, RestTypes...>(forward<Function>(function)); +} + +template <typename FirstType, typename... RestTypes> +template <typename Function> +decltype(auto) Variant<FirstType, RestTypes...>::call(Function&& function) const { + return doCall<Function, FirstType, RestTypes...>(forward<Function>(function)); +} + +template <typename FirstType, typename... RestTypes> +VariantTypeIndex Variant<FirstType, RestTypes...>::typeIndex() const { + return m_typeIndex; +} + +template <typename FirstType, typename... RestTypes> +void Variant<FirstType, RestTypes...>::makeType(VariantTypeIndex typeIndex) { + return doMakeType<FirstType, RestTypes...>(typeIndex); +} + +template <typename FirstType, typename... RestTypes> +bool Variant<FirstType, RestTypes...>::invalid() const { + return m_typeIndex == InvalidVariantType; +} + +template <typename FirstType, typename... RestTypes> +bool Variant<FirstType, RestTypes...>::operator==(Variant const& x) const { + if (this == &x) { + return true; + } else if (typeIndex() != x.typeIndex()) { + return false; + } else { + return call([&x](auto const& t) { + typedef typename std::decay<decltype(t)>::type T; + return t == x.template get<T>(); + }); + } +} + +template <typename FirstType, typename... RestTypes> +bool Variant<FirstType, RestTypes...>::operator!=(Variant const& x) const { + return !operator==(x); +} + +template <typename FirstType, typename... RestTypes> +bool Variant<FirstType, RestTypes...>::operator<(Variant const& x) const { + if (this == &x) { + return false; + } else { + auto sti = typeIndex(); + auto xti = x.typeIndex(); + if (sti != xti) { + return sti < xti; + } else { + return call([&x](auto const& t) { + typedef typename std::decay<decltype(t)>::type T; + return t < x.template get<T>(); + }); + } + } +} + +template <typename FirstType, typename... RestTypes> +template <typename T, typename> +bool Variant<FirstType, RestTypes...>::operator==(T const& x) const { + if (auto p = ptr<T>()) + return *p == x; + return false; +} + +template <typename FirstType, typename... RestTypes> +template <typename T, typename> +bool Variant<FirstType, RestTypes...>::operator!=(T const& x) const { + return !operator==(x); +} + +template <typename FirstType, typename... RestTypes> +template <typename T, typename> +bool Variant<FirstType, RestTypes...>::operator<(T const& x) const { + if (auto p = ptr<T>()) + return *p == x; + return m_typeIndex < TypeIndex<T>::value; +} + +template <typename FirstType, typename... RestTypes> +void Variant<FirstType, RestTypes...>::destruct() { + if (m_typeIndex != InvalidVariantType) { + try { + call([](auto& t) { + typedef typename std::decay<decltype(t)>::type T; + t.~T(); + }); + m_typeIndex = InvalidVariantType; + } catch (...) { + m_typeIndex = InvalidVariantType; + throw; + } + } +} + +template <typename FirstType, typename... RestTypes> +template <typename T> +void Variant<FirstType, RestTypes...>::assign(T&& x) { + typedef typename std::decay<T>::type AssignType; + if (auto p = ptr<AssignType>()) { + *p = forward<T>(x); + } else { + destruct(); + new (&m_buffer) AssignType(forward<T>(x)); + m_typeIndex = TypeIndex<AssignType>::value; + } +} + +template <typename FirstType, typename... RestTypes> +template <typename Function, typename T> +decltype(auto) Variant<FirstType, RestTypes...>::doCall(Function&& function) { + if (T* p = ptr<T>()) + return function(*p); + else + throw BadVariantType(); +} + +template <typename FirstType, typename... RestTypes> +template <typename Function, typename T1, typename T2, typename... TL> +decltype(auto) Variant<FirstType, RestTypes...>::doCall(Function&& function) { + if (T1* p = ptr<T1>()) + return function(*p); + else + return doCall<Function, T2, TL...>(forward<Function>(function)); +} + +template <typename FirstType, typename... RestTypes> +template <typename Function, typename T> +decltype(auto) Variant<FirstType, RestTypes...>::doCall(Function&& function) const { + if (T const* p = ptr<T>()) + return function(*p); + else + throw BadVariantType(); +} + +template <typename FirstType, typename... RestTypes> +template <typename Function, typename T1, typename T2, typename... TL> +decltype(auto) Variant<FirstType, RestTypes...>::doCall(Function&& function) const { + if (T1 const* p = ptr<T1>()) + return function(*p); + else + return doCall<Function, T2, TL...>(forward<Function>(function)); +} + +template <typename FirstType, typename... RestTypes> +template <typename First> +void Variant<FirstType, RestTypes...>::doMakeType(VariantTypeIndex typeIndex) { + if (typeIndex == 0) + *this = First(); + else + throw BadVariantType(); +} + +template <typename FirstType, typename... RestTypes> +template <typename First, typename Second, typename... Rest> +void Variant<FirstType, RestTypes...>::doMakeType(VariantTypeIndex typeIndex) { + if (typeIndex == 0) + *this = First(); + else + return doMakeType<Second, Rest...>(typeIndex - 1); +} + +template <typename... Types> +template <typename T, typename> +constexpr VariantTypeIndex MVariant<Types...>::typeIndexOf() { + return Variant<MVariantEmpty, Types...>::template typeIndexOf<T>(); +} + +template <typename... Types> +MVariant<Types...>::MVariant() {} + +template <typename... Types> +MVariant<Types...>::MVariant(MVariant const& x) + : m_variant(x.m_variant) {} + +template <typename... Types> +MVariant<Types...>::MVariant(MVariant&& x) { + m_variant = move(x.m_variant); + x.m_variant = MVariantEmpty(); +} + +template <typename... Types> +MVariant<Types...>::MVariant(Variant<Types...> const& x) { + operator=(x); +} + +template <typename... Types> +MVariant<Types...>::MVariant(Variant<Types...>&& x) { + operator=(move(x)); +} + +template <typename... Types> +template <typename T, typename> +MVariant<Types...>::MVariant(T const& x) + : m_variant(x) {} + +template <typename... Types> +template <typename T, typename> +MVariant<Types...>::MVariant(T&& x) + : m_variant(forward<T>(x)) {} + +template <typename... Types> +MVariant<Types...>::~MVariant() {} + +template <typename... Types> +MVariant<Types...>& MVariant<Types...>::operator=(MVariant const& x) { + try { + m_variant = x.m_variant; + } catch (...) { + if (m_variant.invalid()) + m_variant = MVariantEmpty(); + throw; + } + return *this; +} + +template <typename... Types> +MVariant<Types...>& MVariant<Types...>::operator=(MVariant&& x) { + try { + m_variant = move(x.m_variant); + } catch (...) { + if (m_variant.invalid()) + m_variant = MVariantEmpty(); + throw; + } + return *this; +} + +template <typename... Types> +template <typename T, typename> +MVariant<Types...>& MVariant<Types...>::operator=(T const& x) { + try { + m_variant = x; + } catch (...) { + if (m_variant.invalid()) + m_variant = MVariantEmpty(); + throw; + } + return *this; +} + +template <typename... Types> +template <typename T, typename> +MVariant<Types...>& MVariant<Types...>::operator=(T&& x) { + try { + m_variant = forward<T>(x); + } catch (...) { + if (m_variant.invalid()) + m_variant = MVariantEmpty(); + throw; + } + return *this; +} + +template <typename... Types> +MVariant<Types...>& MVariant<Types...>::operator=(Variant<Types...> const& x) { + x.call([this](auto const& t) { + *this = t; + }); + return *this; +} + +template <typename... Types> +MVariant<Types...>& MVariant<Types...>::operator=(Variant<Types...>&& x) { + x.call([this](auto& t) { + *this = move(t); + }); + return *this; +} + +template <typename... Types> +bool MVariant<Types...>::operator==(MVariant const& x) const { + return m_variant == x.m_variant; +} + +template <typename... Types> +bool MVariant<Types...>::operator!=(MVariant const& x) const { + return m_variant != x.m_variant; +} + +template <typename... Types> +bool MVariant<Types...>::operator<(MVariant const& x) const { + return m_variant < x.m_variant; +} + +template <typename... Types> +template <typename T, typename> +bool MVariant<Types...>::operator==(T const& x) const { + return m_variant == x; +} + +template <typename... Types> +template <typename T, typename> +bool MVariant<Types...>::operator!=(T const& x) const { + return m_variant != x; +} + +template <typename... Types> +template <typename T, typename> +bool MVariant<Types...>::operator<(T const& x) const { + return m_variant < x; +} + +template <typename... Types> +template <typename T, typename> +T const& MVariant<Types...>::get() const { + return m_variant.template get<T>(); +} + +template <typename... Types> +template <typename T, typename> +T& MVariant<Types...>::get() { + return m_variant.template get<T>(); +} + +template <typename... Types> +template <typename T, typename> +Maybe<T> MVariant<Types...>::maybe() const { + return m_variant.template maybe<T>(); +} + +template <typename... Types> +template <typename T, typename> +T const* MVariant<Types...>::ptr() const { + return m_variant.template ptr<T>(); +} + +template <typename... Types> +template <typename T, typename> +T* MVariant<Types...>::ptr() { + return m_variant.template ptr<T>(); +} + +template <typename... Types> +template <typename T, typename> +bool MVariant<Types...>::is() const { + return m_variant.template is<T>(); +} + +template <typename... Types> +template <typename T, typename> +T MVariant<Types...>::take() { + T t = move(m_variant.template get<T>()); + m_variant = MVariantEmpty(); + return t; +} + +template <typename... Types> +Variant<Types...> MVariant<Types...>::value() const { + if (empty()) + throw BadVariantCast(); + + Variant<Types...> r; + call([&r](auto const& v) { + r = v; + }); + return r; +} + +template <typename... Types> +Variant<Types...> MVariant<Types...>::takeValue() { + if (empty()) + throw BadVariantCast(); + + Variant<Types...> r; + call([&r](auto& v) { + r = move(v); + }); + m_variant = MVariantEmpty(); + return r; +} + +template <typename... Types> +bool MVariant<Types...>::empty() const { + return m_variant.template is<MVariantEmpty>(); +} + +template <typename... Types> +void MVariant<Types...>::reset() { + m_variant = MVariantEmpty(); +} + +template <typename... Types> +MVariant<Types...>::operator bool() const { + return !empty(); +} + +template <typename... Types> +template <typename Function> +void MVariant<Types...>::call(Function&& function) { + m_variant.call(RefCaller<Function>(forward<Function>(function))); +} + +template <typename... Types> +template <typename Function> +void MVariant<Types...>::call(Function&& function) const { + m_variant.call(ConstRefCaller<Function>(forward<Function>(function))); +} + +template <typename... Types> +VariantTypeIndex MVariant<Types...>::typeIndex() const { + return m_variant.typeIndex(); +} + +template <typename... Types> +void MVariant<Types...>::makeType(VariantTypeIndex typeIndex) { + m_variant.makeType(typeIndex); +} + +template <typename... Types> +bool MVariant<Types...>::MVariantEmpty::operator==(MVariantEmpty const&) const { + return true; +} + +template <typename... Types> +bool MVariant<Types...>::MVariantEmpty::operator<(MVariantEmpty const&) const { + return false; +} + +template <typename... Types> +template <typename Function> +MVariant<Types...>::RefCaller<Function>::RefCaller(Function&& function) + : function(forward<Function>(function)) {} + +template <typename... Types> +template <typename Function> +void MVariant<Types...>::RefCaller<Function>::operator()(MVariantEmpty&) {} + +template <typename... Types> +template <typename Function> +template <typename T> +void MVariant<Types...>::RefCaller<Function>::operator()(T& t) { + function(t); +} + +template <typename... Types> +template <typename Function> +MVariant<Types...>::ConstRefCaller<Function>::ConstRefCaller(Function&& function) + : function(forward<Function>(function)) {} + +template <typename... Types> +template <typename Function> +void MVariant<Types...>::ConstRefCaller<Function>::operator()(MVariantEmpty const&) {} + +template <typename... Types> +template <typename Function> +template <typename T> +void MVariant<Types...>::ConstRefCaller<Function>::operator()(T const& t) { + function(t); +} + +} + +#endif |