#ifndef VARIANT_H_ #define VARIANT_H_ #include #include #include #include #include #include #include template T& as(char* memory) { return *std::launder(reinterpret_cast(memory)); } template struct Variant_Helper; template struct Variant_Helper { static constexpr std::size_t const size { std::max(sizeof(Type), Variant_Helper::size) }; static void destroy(char* memory, std::type_index type) { if (typeid(Type) == type) as(memory).~Type(); else Variant_Helper::destroy(memory, type); } }; template <> struct Variant_Helper<> { static constexpr std::size_t const size { 0 }; static void destroy(char*, std::type_index) { throw std::bad_cast{}; } }; template class Variant { private: using Helper = Variant_Helper; char memory[ Helper::size ]; std::type_index type; public: template >> Variant(T&& value) : type { typeid(NormalizedType) } { new (&memory[0]) NormalizedType { std::forward(value) }; } template T& get() { if (typeid(T) == type) return as(&memory[0]); else throw std::bad_cast{}; } template >> Variant& operator=(T&& value) { if (typeid(T) == type) { as(&memory[0]) = std::forward(value); } else { Helper::destroy(&memory[0], type); new (&memory[0]) NormalizedType { std::forward(value) }; type = typeid(NormalizedType); } return *this; } }; #endif