【问题标题】:Iterate over base classes of variadic template class迭代可变参数模板类的基类
【发布时间】:2014-05-04 23:48:02
【问题描述】:

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

这是一个最小的例子:

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++ templates c++11 variadic-templates


【解决方案1】:

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

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

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

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

【讨论】:

  • {(void)((static_cast&lt;U*&gt;(this)-&gt;foo()), 0)...}; -- 如果foo() 返回的内容覆盖operator,
  • @Yakk:纠正错字:{((void)(static_cast&lt;U*&gt;(this)-&gt;foo()), 0)...};
【解决方案2】:

这是一种方法:

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 错误。

【讨论】:

  • 关于评估顺序的要点。我相信我的答案中的数组保证了从左到右的顺序,但我不太记得了。我肯定知道std::initializer_list 确实可以。
  • @chris 两者都由标准保证。 Gcc 的错误仅用于列表初始化,因此您的解决方案可以正常工作。我通常更喜欢我知道会忽略参数的结构(如_do),尽管我猜优化器也会忽略数组。
  • 好的,谢谢。作为旁注,您应该选择different name
  • @chris 我知道这些规则,但如果我理解正确的话,单个下划线只是全局命名空间中的问题,我通常从不在那里定义任何东西(以上只是一个示例) .对吗?
  • 是的,即便如此,请记住 OP 可能不认识他们,他们需要在单独的命名空间中定义它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-29
  • 1970-01-01
  • 2016-09-20
  • 2022-09-22
相关资源
最近更新 更多