【问题标题】:Function operating on each type of a variadic template typelist对可变参数模板类型列表的每种类型进行操作的函数
【发布时间】:2020-12-15 01:07:25
【问题描述】:

我已经定义了一个这样的类型列表:

template <typename ... Types> struct typelist {};

using my_list = typelist<int, double, bool, float>;

现在我有一个函数模板,例如

template<typename T>
void foo() {
    std::cout << typeid(T).name() << std::endl;
}

并希望为类型列表中的每种类型调用它:

foo<int>();
foo<double>();
foo<bool>();
foo<float>();

我试图找到一种递归方式来解决这个问题,但我无法为所需的 foo 函数定义正确的(可能是嵌套的)可变参数模板。你有什么提示可以巧妙地解决这个问题吗?

【问题讨论】:

  • typeid是运算符,没有std::typeid
  • 谢谢,我刚刚意识到并纠正了它

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


【解决方案1】:
template<class... Types> auto foo_foreach(typelist<Types...>) {
     return (foo<Types>(), ...);
}

int main() {
    foo_foreach(my_list{});
}

对于真正的老派,好吧,使用您之前尝试过的模板递归:

void foo_foreach(typelist<>) {}

template<class Head, class... Tail> void foo_foreach(typelist<Head, Tail...>);

template<class Head, class... Tail> void foo_foreach(typelist<Head, Tail...>) {
    foo<Head>();
    foo_foreach(typelist<Tail...>{});
}

【讨论】:

  • 是的,需要对旧版本进行一些调整。
  • 比如这个。
  • @datasailor 抱歉,最初错过了您帖子中的修订标签。
  • 非常感谢 :) 我喜欢 c++17 版本,但现在必须坚持使用 c++14。
【解决方案2】:

这是一个仅使用 lambda 模板的 c++20 答案。

template <typename... Ts, typename C>
constexpr void for_types(C&& c) {
    (c.template operator()<Ts>(), ...);
}

for_types<int, float, char>([]<typename T>()
{
    std::cout << typeid(T).name() << std::endl;
});

【讨论】:

    【解决方案3】:

    如果您需要它来使用 C++14,那么您可以使用 initializer_list 技巧来避免 C++17 折叠表达式。这有望比递归方法更便宜:

    template<class... Ts> void foo_foreach(typelist<Ts...>) {
        (void) std::initializer_list<int>{(foo<Ts>(), 0)...};
    }
    
    int main() {
        foo_foreach(my_list{});
    }
    

    Godbolt 示例:https://godbolt.org/z/o91Th466s

    https://blog.tartanllama.xyz/exploding-tuples-fold-expressions/initializer_list 技巧有一个很好的解释

    来自那篇文章:

    [...] 参数包只能在需要语法列表的上下文中展开,例如初始化程序和函数调用参数。你不能只在函数体中展开它们。在 C++17 中,这个问题有一个很好的解决方案,但在此之前我们需要使用一些非常可怕的 hack。 [...] 一种可能性 [...] 使用 std::initializer_list 创建一个可以扩展参数包的上下文。

    诀窍是 initializer_list 初始化器中的 , 0,它评估函数调用,并使用 0 作为初始化器值。

    【讨论】:

      猜你喜欢
      • 2023-04-02
      • 1970-01-01
      • 2015-11-26
      • 2019-09-01
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      • 2015-08-01
      相关资源
      最近更新 更多