#ifndef CRANY_HPP_ #define CRANY_HPP_ #include <memory> #include <type_traits> #include <cassert> template<template<typename> class = std::is_void> class Crany; /// CranySelf template<> class Crany<> { private: template<template<typename> class> friend class Crany; template<typename T> struct CranySelf { protected: auto & self() { return *((T *)this)->self_; } auto const & self() const { return *((T const *)this)->self_; } virtual ~CranySelf() = default; }; }; /// Crany template<template<typename> class Concept> class Crany final : public Concept<Crany<>::CranySelf<Crany<Concept>>> { public: /// Special member functions template<typename Self> Crany(Self self) : self_{new Model<Self>(std::move(self))} {} Crany(Crany const & other) : self_(other.self_->clone()) {} Crany & operator=(Crany const & other) { return *this = Crany(other); } Crany(Crany && other) = default; Crany & operator=(Crany && other) = default; private: /// CranySelf friend Crany<>::CranySelf<Crany<Concept>>; /// ConceptSelf struct ConceptSelf { protected: auto & self() { assert(!"Crany Concept non-virtual member function called"); return *(Concept<ConceptSelf> *)this; } auto const & self() const { assert(!"Crany Concept non-virtual member function called"); return *(Concept<ConceptSelf> const *)this; } virtual ~ConceptSelf() = default; }; /// CloneConcept struct CloneConcept : Concept<ConceptSelf> { virtual CloneConcept * clone() const = 0; }; /// ModelSelf template<typename T> struct ModelSelf : CloneConcept { protected: auto & self() { return ((T *)this)->self_; } auto const & self() const { return ((T const *)this)->self_; } }; /// Model template<typename Self> struct Model final : Concept<ModelSelf<Model<Self>>> { Model(Self self) : self_{std::move(self)} {} CloneConcept * clone() const { return new Model<Self>(*this); } Self self_; }; /// Self std::unique_ptr<CloneConcept> self_; /// crany_cast template<typename T, typename Crany> friend T const * crany_cast(Crany const * crany) noexcept; template<typename T, typename Crany> friend T * crany_cast(Crany * crany) noexcept; template<typename T, typename Crany> friend T crany_cast(Crany const & crany); template<typename T, typename Crany> friend T crany_cast(Crany & crany); template<typename T, typename Crany> friend T crany_cast(Crany && crany); }; /// bad_crany_cast class bad_crany_cast : public std::bad_cast { }; /// crany_cast template<typename T, typename Crany> T const * crany_cast(Crany const * crany) noexcept { if (!crany) return nullptr; using Model = typename Crany::Model<T>; if (auto * model = dynamic_cast<Model *>(crany->self_.get())) return &model->self_; return nullptr; } template<typename T, typename Crany> T * crany_cast(Crany * crany) noexcept { return const_cast<T *>(*const_cast<T const *>(crany)); } template<typename T, typename Crany> T crany_cast(Crany const & crany) { using U = std::remove_cv_t<std::remove_reference_t<T>>; if (auto p = crany_cast<U>(&crany)) return static_cast<T>(*p); throw bad_crany_cast(); // TODO } template<typename T, typename Crany> T crany_cast(Crany & crany) { using U = std::remove_cv_t<std::remove_reference_t<T>>; if (auto p = crany_cast<U>(&crany)) return static_cast<T>(*p); throw bad_crany_cast(); // TODO } template<typename T, typename Crany> T crany_cast(Crany && crany) { using U = std::remove_cv_t<std::remove_reference_t<T>>; if (auto p = crany_cast<U>(&crany)) return static_cast<T>(std::move(*p)); throw bad_crany_cast(); // TODO } #endif // CRANY_HPP_