2017-04-10 10 views
3

我有一个钻石继承计划,最后一个孩子应该能够继承许多不同的父母。可变参数模板的多重继承:如何为每个基类调用函数?

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

现在想象一下,我有一个class D : public Bclass E : public B, public C等。从D我想打电话给所有的父母,这我保证相同功能存在因继承。我的想法是,我可以用一些可变模板来包装它。

目前我有这样的:

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; } 
}; 

现在,我想我可以做这样的事情,这显然是行不通的:

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();} 
}; 

我希望我可以用它像这样:

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(); 
} 

预期输出(顺序并不重要):

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

我试图实现的可能性是什么?

+2

'INT d ummy [] = {(Args :: doThings(),0)...};'应该诀窍 –

回答

8

一种方式遍历一个可变碱基:

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 
    } 
}; 

或C++ 17,与折叠式:

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

这确实像魅力一样工作!但是我对它的工作原理有点遗憾 - 你能提供一个解释/资源吗? – pingul

+2

您可能会寻找*“遍历一个元组”*。基本上,'...'可以在某种情况下使用,并且我们使用保证评估顺序的一个。 'void()'是处理逗号操作符可能的重载。第一个'0'是处理空'Args ...'。 – Jarod42

2

使用折叠式(C++ 17):

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

Live demo

+2

作为OP标签C++ 11,你应该声明它是C++ 17。 – Jarod42

+0

@ Jarod42它实际上是C++ 14。 –

+1

C++ 17根据[fold_expression](http://en.cppreference.com/w/cpp/language/fold)(和clang给我*“警告:pack fold表达式是一个C++ 1z扩展[ WC++ 1Z的扩展]“*)。 – Jarod42