Skip to content

Instantly share code, notes, and snippets.

@nilium
Last active August 29, 2015 13:56
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 nilium/9026029 to your computer and use it in GitHub Desktop.
Save nilium/9026029 to your computer and use it in GitHub Desktop.
#include <memory>
#include <type_traits>
#include <iostream>
class boxed_t
{
public:
virtual ~boxed_t() = 0;
virtual int type_id() const = 0;
};
boxed_t::~boxed_t()
{
/* nop */
}
template <typename T, int ID>
class boxed_content_t final : public boxed_t
{
using storage_t = typename std::aligned_storage<sizeof(T)>::type;
storage_t storage;
public:
using pointer_t = T *;
using ref_t = T &;
using const_ref_t = T const &;
enum va_tag_t { VA_CTOR_TAG };
enum { TYPE_ID = ID };
boxed_content_t() = delete;
/* Pass VA_CTOR_TAG to dance around ambiguity issues. */
template <typename... VA>
boxed_content_t(va_tag_t tag, VA&&... args) : boxed_t()
{
new (&storage) T(std::forward<VA>(args)...);
}
virtual ~boxed_content_t()
{
pointer()->~T();
}
boxed_content_t(const boxed_content_t &box) : boxed_t()
{
new (&storage) T(*box);
}
boxed_content_t(boxed_content_t &&box) : boxed_t()
{
new (&storage) T(std::move(*box));
}
boxed_content_t &operator = (const boxed_content_t &box)
{
*pointer() = *box;
return *this;
}
boxed_content_t &operator = (boxed_content_t &&box)
{
*pointer() = std::move(*box);
return *this;
}
virtual int type_id() const { return TYPE_ID; }
operator const_ref_t () const { return **this; }
operator ref_t () { return **this; }
pointer_t pointer() const { return (pointer_t)&storage; }
ref_t operator * () { return *pointer(); }
const_ref_t operator * () const { return *pointer(); }
pointer_t operator -> () const { return pointer(); }
};
template <typename T>
struct box_type_id { /* enum { TYPE_ID = *; }; */ };
template <>
struct box_type_id <int> { enum { TYPE_ID = 1 }; };
template <typename T>
using auto_typed_box_t = boxed_content_t<T, box_type_id<T>::TYPE_ID >;
template <typename T>
auto box(T &&content) -> auto_typed_box_t<T>
{
using typed_box_t = auto_typed_box_t<T>;
return typed_box_t(typed_box_t::VA_CTOR_TAG, std::forward<T>(content));
}
template <typename T>
auto box(const T &content) -> auto_typed_box_t<T>
{
using typed_box_t = auto_typed_box_t<T>;
return typed_box_t(typed_box_t::VA_CTOR_TAG, content);
}
template <typename T>
using boxptr_t = std::unique_ptr< auto_typed_box_t<T> >;
template <typename T>
auto make_box(T &&content) -> boxptr_t<T>
{
using typed_box_t = auto_typed_box_t<T>;
return boxptr_t<T>(new typed_box_t(typed_box_t::VA_CTOR_TAG, std::forward<T>(content)));
}
template <typename T>
auto make_box(const T &content) -> boxptr_t<T>
{
using typed_box_t = auto_typed_box_t<T>;
return boxptr_t<T>(typed_box_t(typed_box_t::VA_CTOR_TAG, content));
}
int main(int argc, char const *argv[])
{
boxptr_t<int> foo = make_box(24);
std::cout << *foo << std::endl;
std::cout << foo->type_id() << std::endl;
std::cout << sizeof(*foo) << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment