#include #include #include #include #include template struct static_max; template struct static_max { static const size_t value = arg; }; template struct static_max { static const size_t value = arg1 >= arg2 ? static_max::value : static_max::value; }; template struct variant_helper; template struct variant_helper { inline static void destroy(size_t id, void * data) { if (id == typeid(F).hash_code()) reinterpret_cast(data)->~F(); else variant_helper::destroy(id, data); } inline static void move(size_t old_t, void * old_v, void * new_v) { if (old_t == typeid(F).hash_code()) new (new_v) F(std::move(*reinterpret_cast(old_v))); else variant_helper::move(old_t, old_v, new_v); } inline static void copy(size_t old_t, const void * old_v, void * new_v) { if (old_t == typeid(F).hash_code()) new (new_v) F(*reinterpret_cast(old_v)); else variant_helper::copy(old_t, old_v, new_v); } }; template<> struct variant_helper<> { inline static void destroy(size_t id, void * data) { } inline static void move(size_t old_t, void * old_v, void * new_v) { } inline static void copy(size_t old_t, const void * old_v, void * new_v) { } }; template struct variant { private: static const size_t data_size = static_max::value; static const size_t data_align = static_max::value; using data_t = typename std::aligned_storage::type; using helper_t = variant_helper; static inline size_t invalid_type() { return typeid(void).hash_code(); } size_t type_id; data_t data; public: variant() : type_id(invalid_type()) { } variant(const variant& old) : type_id(old.type_id) { helper_t::copy(old.type_id, &old.data, &data); } variant(variant&& old) : type_id(old.type_id) { helper_t::move(old.type_id, &old.data, &data); } // Serves as both the move and the copy asignment operator. variant& operator= (variant old) { std::swap(type_id, old.type_id); std::swap(data, old.data); return *this; } template void is() { return (type_id == typeid(T).hash_code()); } void valid() { return (type_id != invalid_type()); } template void set(Args&&... args) { // First we destroy the current contents helper_t::destroy(type_id, &data); new (&data) T(std::forward(args)...); type_id = typeid(T).hash_code(); } template T& get() { // It is a dynamic_cast-like behaviour if (type_id == typeid(T).hash_code()) return *reinterpret_cast(&data); else throw std::bad_cast(); } ~variant() { helper_t::destroy(type_id, &data); } }; struct test{ int * holder; test() { std::cout << "test()" << std::endl; holder = new int(); } test(test&& old) : holder(nullptr) { std::cout << "test(test&&)" << std::endl; std::swap(holder,old.holder); } test(const test& old) { std::cout << "test(const test&)" << std::endl; holder = new int(*old.holder); } ~test() { std::cout << "~test()" << std::endl; delete holder; } }; int main() { using my_var = variant; my_var d; d.set("First string"); std::cout << d.get() << std::endl; d.set(); *d.get().holder = 42; my_var e(std::move(d)); std::cout << *e.get().holder << std::endl; *e.get().holder = 43; d = e; std::cout << *d.get().holder << std::endl; }