迭代可变模板类的基类

Iterate over base classes of variadic template class

本文关键字:基类 迭代      更新时间:2023-10-16

如何遍历可变模板类的所有基类并为每个基类调用函数?

下面是一个简单的例子:

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

没有c++ 17的fold表达式通常是不行的。这里的省略号是无效的,星号后面的省略号会创建一个指针模板参数列表。为了重复适当的模式,省略号必须位于语句的末尾,而这在这里不起作用。我发现这篇文章是一个很好的资源包扩展。

相反,的一个技巧,它不需要构建任何递归的东西:
int arr[] = {(static_cast<U*>(this)->foo(), 0)...};

调用每个函数,然后使用带逗号操作符的结果生成所需的int。不幸的是,这可能会导致一个未使用的变量警告。一种最小的方法是使用std::array(或一些可以用初始化器列表初始化的类)并将创建其中一个未命名的类的结果强制转换为void(强制转换为void是一般防止警告的一种常见技术)。

方法如下:

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

但是如果您关心调用的顺序,请注意这里讨论的已知的gcc错误。