迭代可变参数模板类的基类

时间:2014-05-04 23:48:02

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

如何迭代可变参数模板类的所有基类并为每个类调用一个函数。

这是一个最小的例子:

struct A { void foo() { std::cout << "A" << std::endl; } };
struct B { void foo() { std::cout << "B" << std::endl; } };
struct C { void foo() { std::cout << "C" << std::endl; } };

template<typename... U>
struct X : public U...
{
    void foo() {
        static_cast<U*>(this)->foo()...; // ??? should call `foo` for all `U`
    }
};

int main() {
    X<A,B,C> x;
    x.foo();
}

2 个答案:

答案 0 :(得分:9)

通常没有C ++ 17的折叠表达式。那里的省略号无效,星号后面的省略号会创建一个指针模板参数列表。对于要重复的适当模式,省略号必须位于语句的末尾,这在此处不起作用。我发现this article是一个很好的资源包扩展资源。

相反,的一个技巧,它不需要构建任何递归的东西:

int arr[] = {(static_cast<U*>(this)->foo(), 0)...};

这会调用每个函数,然后使用逗号运算符生成所需的int s。不幸的是,这可能会导致未使用的变量警告。解决这个问题的一个最小方法是使用std::array(或者可以使用初始化列表初始化的某个类),并将创建未命名的类的结果转换为void(转换为{{1}一般来说,这是一种防止警告的常用技术。)

答案 1 :(得分:7)

这是一种方式:

struct thru{template<typename... A> thru(A&&...) {}};

struct A { void foo() { std::cout << "A" << std::endl; } };
struct B { void foo() { std::cout << "B" << std::endl; } };
struct C { void foo() { std::cout << "C" << std::endl; } };

template<typename... U>
struct X : public U...
{
    void foo() { thru{(U::foo(), 0)...}; }
};

但如果你关心电话的订单,请注意here所述的已知gcc错误。