Invalid covariant type with CRTP clonable class

invalid covariant return type
crtp constructor
covariant return type c++
c unique_ptr to base class
c++ cloneable
crtp c++ advantages
is not covariant with the return type of the function it overrides
return unique_ptr from function

I'm trying to implement a Clonable class with the CRTP. However, I need to have abstract class that have a pure virtual clone method, overridden by child classes. To make this happen, I need the clone function to return a covariant return type. I made this code below, and the compiler shout at me this error:

main.cpp:12:5: error: return type of virtual function 'clone' is not covariant with the return type of the function it overrides ('B *' is not derived from 'AbstractClonable *')

The class 'B' seems to be a child class of AbstractClonable, and even by two way! How can I solve this? Thank you very much. I tried with both with clang 3.6 and GCC 4.9.2

struct AbstractClonable {
    virtual AbstractClonable* clone() const = 0;
};

template<typename T>
struct Clonable : virtual AbstractClonable {
    T* clone() const override {
        return new T{*dynamic_cast<const T*>(this)};
    }
};

struct A : virtual AbstractClonable {

};

struct B : A, Clonable<B> {

};

Even if B is indeed derived from Clonable<B>, the problem here is that Clonable<B> construction is not valid, as it defines

B* clone() const override

which of course is not an override of AbstractClonable::clone(), since the compiler doesn't see B at this point as a child of AbstractClonable. So I believe the issue lays in the fact that the compiler cannot build the Clonable<B> base of B.

A workaround (but not really the same as what you want) is to define

Clonable* clone() const override

in Clonable. As you mentioned in the comment, you can also define a free function

template<typename T> 
T* clone(const T* object) 
{ 
    return static_cast<T*>(object->clone()); 
}

Related: Derived curiously recurring templates and covariance

c++ - Invalid covariant type with CRTP clonable class -, i'm trying implement clonable class crtp. however, need have abstract class have pure virtual clone method, overridden child classes. make  "invalid covariant return type for" actually caused by the fact that you try to change the return type of getData(). Though return type isn't part of function identifier it still subject for some restriction. Any method that overrides some base class should behave similary.

Yes, B is derived from AbstractClonable, but the compiler doesn't know that during the instantiation of Clonable<B> because B is still incomplete at that point.

C++14 §10.3/8:

If the class type in the covariant return type of D::f differs from that of B::f, the class type in the return type of D::f shall be complete at the point of declaration of D::f or shall be the class type D.

A class has special permission to use itself in a covariant return type. Other classes, including CRTP bases, need to wait until the class is complete before declaring a covariant function.

You can solve the problem using the non-virtual interface idiom (NVI):

class AbstractClonable {
protected:
    virtual AbstractClonable* do_clone() const = 0;
public:
    AbstractClonable *clone() const {
        return do_clone();
    }
};

template<typename T>
class Clonable : public virtual AbstractClonable {
    Clonable* do_clone() const override { // Avoid using T in this declaration.
        return new T{*dynamic_cast<const T*>(this)};
    }
public:
    T *clone() const { // But here, it's OK.
        return static_cast< T * >( do_clone() );
    }
};

How to Return a Smart Pointer AND Use Covariance, The problem: Covariant return type vs. smart pointers class cloneable CRTP is a C++ idiom that enables the injection of the derived class  CRTP: The Curiously Recurring Template Pattern. Since C++98, the main recommended method is to use a variation of CRTP, the Curiously Recurring Template Pattern. The idea is that we instantiate a base class with our own type, and the base class provides the boilerplate we want.

I think the problem is that

T* clone() const override{
    return new T{*dynamic_cast<const T*>(this)};
}

returns B* instead of AbstractClonable *.

C++: Polymorphic cloning and the CRTP (Curiously Recurring , when you define the virtual clone() function in Vehicle as returning an object of type Vehicle, you can override the function in the derived class  Invalid covariant type with CRTP clonable class c++,multiple-inheritance,crtp,cloneable,covariant I'm trying to implement a Clonable class with the CRTP. However, I need to have abstract class that have a pure virtual clone method, overridden by child classes. To make this happen, I need the clone function to return a covariant return type.

Cannot create a proper clone method with shared_ptr – Musing , This requires a feature called covariant return types, which C++ class overriding the virtual function with a different return type. of those 'static_cast' statements will inevitably perform an invalid cast. Take a look at the clonable template in the above code. Using CRTP may solve this in some cases:. c++,multiple-inheritance,c++98,covariant. TL;DR Overriding foo in class D. foo methods can not covariant due to unrelated X and Y return types. Neither, can not overload due to different return types but same signature. Explanation Let's clean up the code to a smaller snippet with same issue: class X {}; class Y {};

GotW-ish: The 'clonable' pattern – Sutter's Mill, CRTP solution is probably the easiest, but most(all?) solutions here suffer from easy to forget issues: 1) the base class needs to have a virtual  Covariant Return Types and Smart Pointers. Covariant Return Types is language feature which allows you to change return type of your virtual function to covariant type ie. pointer to derived class instead of pointer to base class - see example below:

Using CRTP with virtual inheritance - c++ - android, Every node must be clonable but I don't want to write clone method to every node​. So I use CRTP. class Node { public: Node(){} Node(Fill*) { } virtual ~Node() Is there a way to overcome the bug, and still have covariant types is clone method? be syntactically invalid and has no meaningful semantics with regards to C++. As you can see, the concrete class is now free of clutter. This effectively adds a polymorphic and covariant clone() to a hierarchy of class. This CRTP is the foundation of our general solution: Every next step will build upon it. Multiple Inheritance: Variadic templates to the rescue. One complication of OO hierarchies is multiple inheritance.

Comments
  • Do you really need AbstractClonable? Why? I'm really curious. Are there legitimate use cases? You can clone it, and what would you do with the result? Clone it again?
  • Yes. If I have a collection of A and A is abstract and I need to clone each object, I need something that says that I need to implement clone in subclasses. Since A is abstract, it cannot inherits from Clonable, because of the new in the clone function. I came up with AbstractClonable.
  • shouldn't virtual inheritance take care of that?
  • AFAIK, the virtual derivation just removes the "duplicate" base from the picture. I don't think it makes this construction work.
  • B is a child of A and A is a child of AbstractClonable. And we can see that B is a child of the class Clonable<B>, which is a child of AbstractClonable. B is related to AbstractClonable two times. How's that B is not a child of AbstractClonable?
  • B is a child of AbstractClonable, but when first constructing Clonable<B>, B is an incomplete type, and Clonable<B> is not seen as a child of AbstractClonable. I don't think the compiler can successfully fully define B without first trying to resolve its base classes. I have to say I am not 100% sure of this. Related (but without an accepted answer) stackoverflow.com/q/17201268/3093378
  • It certainly not the semantic I was looking for, but it will do the trick I guess
  • Yes it returns a B*, and it's my goal! Shouldn't they be valid covariant types since B inherits from AbstractClonable?
  • Since there is a multiple virtual inheritance involved casting from B* to AbstractClonable* requires additional code to be emitted. This code will perform base class lookup using pointer to a virtual base class. If you call clone() method using a pointer to AbstractClonable compiler probably is not able to perform typecasting properly. So I don't think B* and AbstractClonable* can be considered covariant.