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

时光毁灭记忆、已成空白 提交于 2019-12-07 04:16:01

问题


I have a diamond inheritance scheme, where the last child should be able to inherit from many different parents.

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

Now imagine I have a class D : public B, class E : public B, public C, etc. From D I want to call the same function of all its parents, which I am guaranteed exists due to the inheritance. My thought was that I could wrap this in some variadic template.

Currently I 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 obviously does not 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();}
};

My hope is that I can use it like so:

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 output (order does not matter):

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

Is what I'm trying to achieve possible?


回答1:


One way to iterate over the variadic 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 folding expression:

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



回答2:


Use a fold-expression (C++17):

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

Live demo



来源:https://stackoverflow.com/questions/43322854/multiple-inheritance-with-variadic-templates-how-to-call-function-for-each-base

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!