1

I came up with a "pattern" or whatever it's called and just wanted to ask experts if it's a good design and what could be some possible problems with it. In my real code, I have functions that do some matrix operations. I want them to be templatable by various matrix implementations, that should all have the same public methods. To let's say enforce this common interface, I want to have an abstract base class that will prescribe the interface.

The snippet code shows the idea. A templated base class that defines an interface. Then some derived classes that all implement the same functionality (note that they are forced to otherwise they won't be able to instantiate). The weird thing that I used is that the template parameter for A in the derived class definitions is the derived class itself, not sure if that is a good idea?

Note that I am aware that classes B, C and D actually don't derive from the same class, but that's not something I need. I just want to enforce a common interface for all the derived classes to make it clear what should be implemented.

I am also aware that the AddTwoWhatever function can easily be used with some other template arguments that have nothing to do with the base class A, but I am fine with that too. I am not trying to achieve a template restriction, just provide a guideline for new implementations of A behaviour.

So to summarise, I have the design shown in the attached code and I would like to ask if it's a good idea, if it will work, what are possible issues with it?

template <class T>
class A
{
public:
    virtual void Add(const T& aOther) = 0;
    virtual void PrintValue() const = 0;
};

class B : public A<B>
{
private:
    int mValInt;

public:
    B(int aVal) : mValInt(aVal) { }
    virtual void Add(const B& aOther) override
    {
        mValInt += aOther.mValInt;
    }
    virtual void PrintValue() const override
    {
        std::cout << mValInt << std::endl;
    }
};

class C : public A<C>
{
private:
    double mValDouble;
public:
    C(double aVal) : mValDouble(aVal) { }
    virtual void Add(const C& aOther) override
    {
        mValDouble += aOther.mValDouble;
    }
    virtual void PrintValue() const override
    {
        std::cout << mValDouble<< std::endl;
    }
};

class D : public A<D>
{
private:
    float mValFloat;
};

template <class T>
void AddTwoWhatever(T aFirst, T aSecond)
{
    T aResult(0);

    aResult.Add(aFirst);
    aResult.Add(aSecond);

    aResult.PrintValue();
}

int main(int argc, char **argv) 
{
    B b1(10);

    B b2(11);

    b1.Add(b2);

    b1.PrintValue();

    C c1(13.9);

    C c2(16.3);

    // b1.Add(c1); // gives compile time error as I want it to

    AddTwoWhatever(b1, b2);
    AddTwoWhatever(c1, c2);

    // AddTwoWhatever(b1, c2); // again, gives error as intended

    // D d; // gives compile time error because D is abstract (not implementing A), again, something that I want, enforce the A implementation

    return 0;
}
  • 5
    It's called the [Curiously Recurring Template Pattern](https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern). – David G Jul 08 '19 at 17:27

0 Answers0