#include #include namespace sprawl { namespace memory { template class OpaqueType; template struct CreateAs{}; } } #if (defined(_WIN32) && _MSC_VER < 1900) # define alignof __alignof #endif template class sprawl::memory::OpaqueType { public: class Deleter { public: virtual void Delete(void*) = 0; }; template class TypeDeleter : public Deleter { public: virtual void Delete(void* ptr) { reinterpret_cast(ptr)->~T(); } }; template OpaqueType(CreateAs const&, Params&&... params) : m_ptr() , m_deleter() { static_assert(sizeof(T) == size, "Opaque type delcared with size that does not match the type used to construct it."); static_assert(align >= alignof(T) && (align % alignof(T) == 0), "Opaque type definition does not match alignment requirements of the type used to construct it."); new(&m_ptr) T(std::forward(params)...); new(&m_deleter) TypeDeleter(); } ~OpaqueType() { reinterpret_cast(&m_deleter)->Delete(&m_ptr); } template T& As() { static_assert(sizeof(T) == size, "Opaque type delcared with size that does not match the type used to access it."); static_assert(align >= alignof(T) && (align % alignof(T) == 0), "Opaque type definition does not match alignment requirements of the type used to access it."); return *reinterpret_cast(&m_ptr); } template T const& As() const { static_assert(sizeof(T) == size, "Opaque type delcared with size that does not match the type used to access it."); static_assert(align >= alignof(T) && (align % alignof(T) == 0), "Opaque type definition does not match alignment requirements of the type used to access it."); return *reinterpret_cast(&m_ptr); } template operator T&() { static_assert(sizeof(T) == size, "Opaque type delcared with size that does not match the type used to access it."); static_assert(align >= alignof(T) && (align % alignof(T) == 0), "Opaque type definition does not match alignment requirements of the type used to access it."); return *reinterpret_cast(&m_ptr); } template operator T const&() const { static_assert(sizeof(T) == size, "Opaque type delcared with size that does not match the type used to access it."); static_assert(align >= alignof(T) && (align % alignof(T) == 0), "Opaque type definition does not match alignment requirements of the type used to access it."); return *reinterpret_cast(&m_ptr); } private: typename std::aligned_storage::type m_ptr; typename std::aligned_storage::type m_deleter; };