Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A polymorphic collection of Curiously Recurring Template Pattern (CRTP) in C++?

I've got a class Base from which I have two classes, DerivedA and DerivedB as defined below.

template <typename Derived>
class Base{
public:
    double interface(){
        static_cast<Derived*>(this)->implementation();
    }
};

class DerivedA : public Base<DerivedA>{
public:
    double implementation(){ return 2.0;}
};

class DerivedB : public Base<DerivedB>{
public:
    double implementation(){ return 1.0;}
};

In short, I'm trying to do the following to maintain a collection of objects, some of which are DerivedA and some of which are DerivedB:

std::vector<std::shared_ptr<Derived>>

Which is obviously impossible beacuse I've now made the class Derived a templated class.

Is there any way I can create / maintain a polymorphic collection of objects?

EDIT: Unfortunately, a simple templated structure does not work as the function implementation is templated in my actual program -- so then implementation would have to be a templated pure virtual function, which cannot be. Pardon my lack of explanation.

like image 227
druckermanly Avatar asked Dec 01 '22 01:12

druckermanly


2 Answers

This answer pertains to the question as it was at the time of this answer.


Don't use CRTP, which is not dynamic polymorphism, to create dynamic polymorphism.

Use a virtual function.

That's what they're for.

class Base
{
private:
    virtual
    auto implementation() -> double = 0;

public:
    auto interface() -> double { return implementation(); }
};

class DerivedA
    : public Base
{
private:
    auto implementation() -> double override { return 2.0; }
};


class DerivedB
    : public Base
{
private:
    auto implementation() -> double override { return 1.0; }
};
like image 169
Cheers and hth. - Alf Avatar answered Dec 04 '22 12:12

Cheers and hth. - Alf


Alf's suggestion is on target. It is easy to adapt it to your additional requirement. Define an interface with a pure virtual method:

struct BaseInterface {
    virtual ~BaseInterface() {}
    virtual double interface() = 0;
};

Now, your template base class can derive from the interface:

template <typename Derived>
class Base : BaseInterface {
public:
    double interface(){
        static_cast<Derived*>(this)->implementation();
    }
};

Now, you can create a vector of pointers to the interface:

std::vector<std::shared_ptr<BaseInterface>>
like image 33
jxh Avatar answered Dec 04 '22 13:12

jxh