If you can use a different syntax to specify full types, you can do the following (warning: untested code):
Start with the machine first:
// this gives the complete type which needs to be used to create objects // and provides the implementation of clone() template<typename T> class Cloneable: public T { public: template<typename... U> Cloneable(U&&... u): T(std::forward<U>(u) ...) {} T* clone() { return new Cloneable(*this); } private: // this makes the class complete // Note: T:: to make it type dependent, so it can be found despite not yet defined typename T::CloneableBase::CloneableKey unlock() {} }; // this provides the clone function prototype and also makes sure that only // Cloneable<T> can be instantiated class CloneableBase { template<typename T> friend class Cloneable; // this type is only accessible to Clonerable instances struct CloneableKey {}; // this has to be implemented to complete the class; only Cloneable instances can do that virtual CloneableKey unlock() = 0; public: virtual CloneableBase* clone() = 0; virtual ~CloneableBase() {} };
OK, now the actual class hierarchy. This is pretty standard; no CRTP intermediates or other complications. However, no class implements the clone function, but all inherit the declaration (directly or indirectly) from CloneableBase .
// Base inherits clone() from CloneableBase class Base: public CloneableBase { // ... }; // Derived can inherit normally from Base, nothing special here class Derived: public Base { // ... };
Here, as you then create the objects:
// However, to create new instances, we actually need to use Cloneable<Derived> Cloneable<Derived> someObject; Derived* ptr = new Cloneable<Derived>(whatever); // Now we clone the objects Derived* clone1 = someObject.clone(); Derived* clone2 = ptr->clone(); // we can get rid og the objects the usual way: delete ptr; delete clone1; delete clone2;
Note that a Cloneable<Derived> is-a Derived (this is a subclass), so you only need to use Cloneable for construction, and otherwise you can pretend to work with Derived objects (well, tyepinfo also identifies it as Cloneable<Derived> ).
celtschk
source share