【问题标题】:Multiple inheritance with variadic templates: how to call function for each base class?可变参数模板的多重继承:如何为每个基类调用函数?
【发布时间】:2017-04-10 12:13:14
【问题描述】:

我有一个钻石继承计划,其中最后一个孩子应该能够从许多不同的父母那里继承。

     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 // <--

我正在努力实现的目标可能吗?

【问题讨论】:

  • int dummy[] = { (Args::doThings(), 0)... }; 应该可以解决问题

标签: c++ c++11 variadic-templates


【解决方案1】:

一种迭代可变参数基的方法:

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

【讨论】:

  • 这确实很有魅力!然而,我对它的工作原理有点迷茫——你能提供解释/资源吗?
  • 你可以寻找 "iterate over a tuple"。基本上,... 可以在某些情况下使用,我们使用一种保证评估顺序的方法。 void() 用于处理可能的逗号运算符重载。第一个0 是处理空的Args...
【解决方案2】:

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

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

Live demo

【讨论】:

  • 作为OP标签C++11,你应该声明它是C++17。
  • @Jarod42 实际上是 C++14。
  • c++17 根据fold_expression(并且clang给了我“警告:pack fold表达式是C++1z扩展[-Wc++1z-extensions]” i>)。
  • @Jarod42 hmm 看起来它是 n4296 中不在官方 14 标准中的东西之一。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-15
  • 2012-05-12
  • 2012-03-13
  • 1970-01-01
  • 2019-04-25
  • 1970-01-01
  • 2013-03-25
相关资源
最近更新 更多