【问题标题】:Loop a list of typedefs循环一个 typedef 列表
【发布时间】:2018-07-09 13:26:33
【问题描述】:

如果标题有点误导,我很抱歉。

我有一个循环一些数据的函数。每次迭代时,此数据的类型都会发生变化。

基本上我有这样的东西:

for(int i = 0; i < limit; i++)
{
  type object;
  object.do_stuff();
}

例如,在第一次迭代中,“type”将为 int,在第二次迭代中,“type”将为 double,等等。

我不能使用可变模板,因为我有 100 多个元素,据我所知,这对系统来说会非常繁重。

我的想法是创建一个“typedef 向量”来循环对象的所有类型。

vector<????> type;
type.push_back(int);
type.push_back(double);
...
for(int i = 0; i < limit; i++)
{
  type[i] object;
  object.do_stuff();
}

我不知道这是否可能。

我看到了类型列表的基础知识,但我不知道是否可以重现循环。

【问题讨论】:

  • 您在寻找std::tuple 吗?
  • int::do_stuff 将是无效的顺便说一句。
  • 你真的尝试过可变参数模板吗? “据我所知,这对系统来说会很费力”编译可能需要更长的时间,但应该没有运行时开销。
  • 按照你的逻辑,一个程序永远不应该包含 100 个不同类型的向量。这似乎很不合理
  • @Jarod42 我不知道元组!当然看起来元组是我要找的,谢谢!是的,关于 int::do_stuff 这是我在编写示例时的错误,应该是 int a;一个::do_stuff。 HolyBlackCat & Default 我试过了,但我的经理告诉我,如果我在一个可变模板中超过 20 种类型,系统将变得太慢。尽可能缩短编译时间很重要。

标签: c++ arrays metaprogramming typedef


【解决方案1】:

我不能使用可变模板,因为我有 100 多个元素,据我所知,这对系统来说会非常繁重。

您所知道的要么是过时的,要么是不准确的。只需查看 metaben.ch 即可了解类型列表可以在多大程度上获得编译时间影响。


我的想法是创建一个“typedef 向量”来循环对象的所有类型。

这是一个类型列表。您可以执行以下操作:

// Store the type in a value for convenience
template <typename T>
struct type_wrapper
{
    using type = T;
};

template <typename... Ts>
struct typelist
{
    template <typename F>
    constexpr void for_each(F&& f)
    {
        // C++17 fold expression over comma operator
        (f(type_wrapper<Ts>{}), ...);
    }
};

C++17 用法:

typelist<int, float, char>{}.for_each([](auto t)
{
    using type = typename decltype(t)::type;
    // Use `type`
});

C++20 用法(对typelist 稍作改动):

template <typename... Ts>
struct typelist
{
    template <typename F>
    constexpr void for_each(F&& f)
    {
        // C++17 fold expression over comma operator
        (f.template operator()<Ts>(), ...);
    }
};

typelist<int, float, char>{}.for_each([]<typename T>()
{
    // Use `T`
});

我写了一篇与这个主题相关的短文:"compile-time iteration with C++20 lambdas "

【讨论】:

  • 我真的很喜欢这个,但我最多只能使用 c++ 11。这是在处理它还是需要 c++17?
  • 遗憾的是,这在 C++11 中更难做到。您需要将 fold 表达式 替换为 initializer_list(参见 my talk on the subject),并将通用 lambda 替换为具有模板化 operator()struct。使用语法不会那么好。不过,如果没有递归,这绝对是可能的。
  • 好的,谢谢。在这种情况下,最好有一个 std::tuple 列表来存储所有类型并循环它们?
  • 使用std::tuple 不会改变我在上面评论中所说的内容。你仍然需要这些东西才能在 C++11 中完成这项工作,而且它永远不会像 C++11/14 那样好。
  • 好吧,我想有总比没有好。谢谢你非常详细的解释!
【解决方案2】:

我们可以用稍微不同的方式来看待这个问题,并说您可能真正想要的是一个要做的事情的向量(或者,我可能更愿意说,列表) ,这可以通过 中的一些工具以非常通用的方式实现。一起来看看吧:

#include <vector>
#include <functional>
#include <iostream>

static void process_int (int i) { std::cout << "process_int " << i << "\n"; }
static void process_string (std::string s) { std::cout << "process_string " << s << "\n"; }
// ...                                            

int main()
{
    std::vector <std::function <void ()>> v;

    v.push_back (std::bind (process_int, 42));
    v.push_back (std::bind (process_string, "Hello world"));

    for (auto f : v)
        f ();                    
}

输出:

process_int 42
process_string Hello world

它再简单不过了,你可以用各种聪明(或不那么聪明)的方式来调整它,以适应你的特定用例。正如现场演示所示,在 C++11 中应该没问题。您还可以将 lambda 传递给 std::bind

Live demo.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-09
    • 2022-01-06
    相关资源
    最近更新 更多