1c2b77f6 |
#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_
|