Skip to content

Instantly share code, notes, and snippets.

@Ferdi265
Created June 2, 2020 17:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Ferdi265/7b44b35c5419ab893fcccf494584787d to your computer and use it in GitHub Desktop.
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
#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();
}
#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