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