Last active
August 29, 2015 13:56
-
-
Save nilium/9026029 to your computer and use it in GitHub Desktop.
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 <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