Created
June 2, 2020 17:22
-
-
Save Ferdi265/7b44b35c5419ab893fcccf494584787d to your computer and use it in GitHub Desktop.
virtual_base_union -- a union class that functions as a smart pointer to a polymorphic type
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <string> | |
#include "virtual_base_union.h" | |
class Screen { | |
public: | |
virtual ~Screen() = default; | |
virtual void draw() = 0; | |
}; | |
class Screen1 : public Screen { | |
private: | |
int x; | |
int y; | |
public: | |
Screen1(int x, int y) : x(x), y(y) {} | |
void draw() override { | |
std::cout << "drawing Screen1: " << x << " " << y << "\n"; | |
} | |
~Screen1() { | |
std::cout << "destructing Screen1\n"; | |
} | |
}; | |
class Screen2 : public Screen { | |
private: | |
std::string name; | |
public: | |
Screen2(std::string name) : name(name) {} | |
void draw() override { | |
std::cout << "drawing Screen2: " << name << "\n"; | |
} | |
~Screen2() { | |
std::cout << "destructing Screen2\n"; | |
} | |
}; | |
int main() { | |
virtual_base_union<Screen, Screen1, Screen2> scr; | |
scr.construct<Screen1>(3, 4); | |
scr->draw(); | |
scr.virtual_reconstruct<Screen2>("hello"); | |
scr->draw(); | |
scr.virtual_destruct(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <utility> | |
#include <type_traits> | |
namespace __detail { | |
template <typename... Ts> | |
class multi_union; | |
template <typename T, typename... Ts> | |
class multi_union<T, Ts...> { | |
private: | |
union { | |
multi_union<Ts...> rest; | |
T t; | |
}; | |
public: | |
multi_union() {} | |
~multi_union() {} | |
template <typename U> | |
U& get() { | |
if constexpr (std::is_same_v<T, U>) { | |
return t; | |
} else { | |
return rest.template get<U>(); | |
} | |
} | |
template <typename U> | |
const U& get() const { | |
if constexpr (std::is_same_v<T, U>) { | |
return t; | |
} else { | |
return rest.template get<U>(); | |
} | |
} | |
}; | |
template <> | |
class multi_union<> {}; | |
template <typename Base, typename... Derived> | |
class is_base_of_all; | |
template <typename Base, typename D, typename... Ds> | |
class is_base_of_all<Base, D, Ds...> { | |
public: | |
constexpr static bool value = std::is_base_of<Base, D>::value && is_base_of_all<Base, Ds...>::value; | |
}; | |
template <typename Base> | |
class is_base_of_all<Base> { | |
public: | |
constexpr static bool value = true; | |
}; | |
template <typename Target, typename... Types> | |
class is_same_as_any; | |
template <typename Target, typename T, typename... Ts> | |
class is_same_as_any<Target, T, Ts...> { | |
public: | |
constexpr static bool value = std::is_same<Target, T>::value || is_same_as_any<Target, Ts...>::value; | |
}; | |
template <typename Target> | |
class is_same_as_any<Target> { | |
public: | |
constexpr static bool value = false; | |
}; | |
class empty {}; | |
} | |
template <typename Base, typename D1, typename... Derived> | |
class base_union : private std::enable_if<__detail::is_base_of_all<Base, D1, Derived...>::value, __detail::empty>::type { | |
private: | |
__detail::multi_union<D1, Derived...> values; | |
public: | |
base_union() {} | |
~base_union() {} | |
template <typename D, typename... Ts, | |
typename = std::enable_if<__detail::is_same_as_any<D, D1, Derived...>::value> | |
> | |
void construct(Ts... ts) { | |
new (&values.template get<D>()) D(std::forward<Ts>(ts)...); | |
} | |
template <typename D, | |
typename = std::enable_if<__detail::is_same_as_any<D, D1, Derived...>::value> | |
> | |
void destruct() { | |
values.template get<D>().~D(); | |
} | |
template <typename Old, typename New, typename... Ts, | |
typename = std::enable_if<__detail::is_same_as_any<Old, D1, Derived...>::value>, | |
typename = std::enable_if<__detail::is_same_as_any<New, D1, Derived...>::value> | |
> | |
void reconstruct(Ts... ts) { | |
destruct<Old>(); | |
construct<New, Ts...>(std::forward<Ts>(ts)...); | |
} | |
template <typename D, | |
typename = std::enable_if<__detail::is_same_as_any<D, D1, Derived...>::value> | |
> | |
D& get() { | |
return values.template get<D>(); | |
} | |
template <typename D, | |
typename = std::enable_if<__detail::is_same_as_any<D, D1, Derived...>::value> | |
> | |
const D& get() const { | |
return values.template get<D>(); | |
} | |
Base& get() { | |
return get<D1>(); | |
} | |
const Base& get() const { | |
return get<D1>(); | |
} | |
Base& operator*() { | |
return get(); | |
} | |
const Base& operator*() const { | |
return get(); | |
} | |
Base* operator->() { | |
return &get(); | |
} | |
const Base* operator->() const { | |
return &get(); | |
} | |
}; | |
template <typename Base, typename D1, typename... Derived> | |
class virtual_base_union : public base_union<Base, D1, Derived...> { | |
public: | |
void virtual_destruct() { | |
(*this)->~Base(); | |
} | |
template <typename New, typename... Ts, | |
typename = std::enable_if<__detail::is_same_as_any<New, D1, Derived...>::value> | |
> | |
void virtual_reconstruct(Ts... ts) { | |
virtual_destruct(); | |
this->template construct<New, Ts...>(std::forward<Ts>(ts)...); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment