Multiple inheritance with variadic templates: how to call a function for each base class?

I have a diamond inheritance scheme where the last child must inherit from many different parents.

     A
    /|\
   / | \
  B  C  ...
  |  |  |
    * *
    D E

      

Now imagine what I have class D : public B

, class E : public B, public C

etc. From D

I want to call the same function of all my parents, which I am guaranteed to exist due to inheritance. My thought was that I could wrap this in some kind of variational pattern.

I currently have this:

template <typename T>
class A
{
public:
    A(T t) : mT(t) {}
    virtual ~A() {}
    virtual void doThings() = 0;
protected:
    T mT;
};

template <typename T, typename A = A<T>>
class B : public A
{
public:
    B(T t) : A(t) {}
    virtual ~B() {}
    virtual void doThings() { std::cout << "B" << std::endl; }
};

template <typename T, typename A = A<T>>
class C : public A
{
public:
    C(T t) : A(t) {}
    virtual ~C() {}
    virtual void doThings() { std::cout << "C" << std::endl; }
};

      

Now I thought I could do something like this, which clearly doesn't work:

template <typename T, typename ...Args>
class ChildGenerator : public Args...
{
public:
    ChildGenerator(T t) : Args(t)... {}

    // The unpacking of the variadic template does not work here.
    // Do I need to make it recursive somehow? How can I do that without having to instantiate new classes B and C?
    void doThings() override { Args...::doThings();}
};

      

I hope I can use it like this:

int main()
{
    using B = B<double>;
    using C = C<double>;
    B c1(0.0);
    C c2(1.0);
    ChildGenerator<double, B, C> c3(2.0);
    c1.doThings();
    c2.doThings();
    c3.doThings();
 }

      

Expected result (order doesn't matter):

B
C
B // <-- order of these two does not matter
C // <--

      

Am I trying to achieve something?

+3


source to share


2 answers


One way to repeat variable bases:

template <typename T, typename ...Args>
class ChildGenerator : public Args...
{
public:
    ChildGenerator(T t) : Args(t)... {}

    void doThings() override {
        int dummy[] = {0, (Args::doThings(), void(), 0)...};
        static_cast<void>(dummy); // avoid warning for unused variable
    }
};

      



or in C ++ 17, with a folding expression:

    void doThings() override {
        (static_cast<void>(Args::doThings()), ...);
    }

      

+8


source


Use fold-expression (C ++ 17):

void doThings() override { ((Args::doThings()) , ...);}

      



Live demo

+2


source







All Articles