3

In my current project, I need to be able to provide template-based multiple inheritance (Mixin pattern) and have two classes (with mirroring multiple-inheritance trees) that can interact together (i.e. one uses methods from the other one at the same inheritance level).

Long story short, I cannot seem to find an elegant way to build this. Below is a reduced testcase (you can run and edit it directly here).

Is there a pattern or trick that would let me have something similar to the commented line while keeping any subclasses relatively cruft-free?

Obviously, the nested Thing class would need to inherit from another class providing the necessary interface methods. However any attempt at fixing the inheritance problem (CRTP...) always seem to lead me to recursive inheritance or incomplete base type issues...

class Base {
public:

    class Thing {
    public:
        Thing(Base& b) : _b(b) {};

        Thing& operator+= (const Thing p) { _b.add(*this, p); return *this; };

        int k;
    protected:
        Base& _b;
    };

    void add(Thing &d, const Thing s) { d.k += s.k; }
};

template <class... Interfaces>
class Extensible : virtual public Base, virtual public Interfaces... {

    class Thing : virtual public Base::Thing, virtual public Interfaces::Thing... {

    };
};

class SomeInterface : Base {
    void multiply(Thing &d, const Thing s) { d.k *= s.k; }

    class Thing : public Base::Thing {
        Thing& operator*= (const Thing p) {
            //_b.multiply(*this, p); return *this; // <-- won't work of course
        };

    };

};

int main() {
    Extensible<SomeInterface> a;
    return 0;
}
Dave
  • 291
  • 2
  • 13

1 Answers1

1

This is one of the options: http://ideone.com/KhLyfj (I just tell the base class what is its subclass to give _b a correct type). It won't work in some situations though. You can experiment with moving the template from Thing/add straight to Base.

class Base {
public:

    template<typename Outer>
    class Thing {
    public:
        Thing(Base& b) : _b(b) {};

        Thing& operator+= (const Thing p) { _b.add(*this, p); return *this; };

        int k;
    protected:
        Outer& _b;
    };

    template<typename Outer>
    void add(Thing<Outer> &d, const Thing<Outer> s) { d.k += s.k; }
};

template <class... Interfaces>
class Extensible : virtual public Base, virtual public Interfaces... {

    class Thing : virtual public Base::Thing<Base>, virtual public Interfaces::template Thing<Base>... {

    };
};

class SomeInterface : Base {
    void multiply(Thing<SomeInterface> &d, const Thing<SomeInterface> s) { d.k *= s.k; }

    class Thing : public Base::Thing<SomeInterface> {
        Thing& operator*= (const Thing p) {
            _b.multiply(*this, p); return *this; // <-- will work of course
        };

    };

};

int main() {
    Extensible<SomeInterface> a;
    return 0;
}
matb
  • 227
  • 2
  • 7
  • Thanks for the suggestion: it sounds like a promising direction (had to make some additions for it to let me instantiate `Thing` objects). Except this leads to diamond problems where it is impossible to use `_b` in the main class: http://ideone.com/YrrpBn – Dave Dec 04 '14 at 08:05
  • Try this out, then: http://ideone.com/TOKP8b . I've added forward declaration of `SomeInterface`, `Base` is a virtual base class for `Extensible`, `SomeInterface::Thing` has an explicit constructor, `Extensible::Thing`'s constuctor explicitly calls `Base::Thing::Thing(e)`. It was a very nice puzzle :). – matb Dec 04 '14 at 10:41
  • Thanks a lot for your effort... unfortunately, the forward declaration (and use inside Extensible) sort of defeats the purpose of the Interface patterns (by requiring us to preemptively inheriting from all interfaces we have). I managed to get some code working at: http://ideone.com/sblnfM Anyway, I am marking your answer as accepted. Feel free to merge it with this code. – Dave Dec 04 '14 at 18:08