【问题标题】:Automaticaly convert array of structures to structure of arrays in C++自动将结构数组转换为 C++ 中的数组结构
【发布时间】:2018-05-02 05:55:06
【问题描述】:

我有一个结构体Widget,里面有几个字段:

struct Widget
{
    Some field1;
    Another second_field;
    ...
};

从概念上讲,我需要这些小部件的数组或向量,即std::vector<Widget>。但出于性能原因,所有这些字段都应该在它自己的数组中,即:

struct Widgets
{
    vector<Some> field1;
    vector<Another> second_field;
    ...
};

那么,鉴于Widget 在 C++ 中有哪些可能的方法可以将其字段分散在多个向量上,即将结构数组转换为字段数组结构?手动定义一些合理的元数据是可以的(在Widget内部或外部),但首选没有额外元数据的解决方案。

为了澄清,我正在寻找一种将Widget 结构转换为Widgets 结构的自动或半自动方法,而无需手动编码所有样板胶水。

【问题讨论】:

  • 我几乎可以肯定您需要第三方工具来实现这一点。也许元类能够做到这一点,但我认为它们不可能在 2023 年之前使用该语言。
  • 无法自动执行此操作。你必须用艰难的方式。

标签: c++ metaprogramming


【解决方案1】:

可以使用std::transform 和一些 lambda 函数来实现核心功能。

要从std::vector&lt;Widget&gt; 获取std::vector&lt;Some&gt;,请使用:

 std::vector<Widget> v1 = { ... };
 std::vector<Some> v2(v1.size());
 std::transform(v1.begin(),
                v1.end(),
                v2.begin(),
                [](Widget const& w) -> Some { return w.field1; });

我会让你弄清楚其余的。

我正在寻找一种将Widget 结构转换为Widgets 结构的自动或半自动方式,而无需手动编码所有样板胶水。

您必须为Widget 的每个成员变量编写一些样板代码。通过使用自己的辅助函数,您将能够稍微减少样板代码的数量。

例如

template <typename FieldType, typename Lambda>
void scatter(std::vector<Widget> const& widgets,
             std::vector<FieldType>& fields,
             Lmabda l)
{
   fields.resize(widgets.size());
   std::transform(widgets.begin(), widgets.end(), fields.begin(), l);
}

并将其用作:

 std::vector<Widget> v1 = { ... };
 Widgets w;
 scatter(v1, w.field1, [](Widget const& w) -> Some { return w.field1; });
 scatter(v1, w.second_field, [](Widget const& w) -> Another { return w.second_field; });
 ...

【讨论】:

  • 澄清一下,主要步骤是将Widget 类型转换为Widgets 类型,如Q 中所述,这是缺失的。
  • @mechanical,我假设我的答案包含足够的信息,让您能够编写代码来充实Widgets 对象的内容。
  • 首先,我需要转换类型,而不是数据。数据本身可以填充到转换类型的实例中,不需要对数据进行运行时转换。
  • @mechanical,您对您的问题没有答案,但您声称了解 C++ 中的可能性和定义明确的操作。谦虚一点会有所帮助。
  • @mechanical 没有意识到您在谈论元编程,抱歉。没有元函数可以将用户定义的类类型转换为其字段的类型列表或类似的东西。在反射被添加到 C++ 之前。
【解决方案2】:

您可以重载[] 运算符,以便内存中相邻的成员(如第二个示例),但您可以表现得好像有一个结构向量:

struct Widget { 
  Some &field1; Another &second_field; ... 
  Widget(Some &f1, Another &f2 ...) : field1(f1), second_field(f2) ... {};
};

struct Widgets
{
   Widgets(int size) : field1(size), second_field(size) ... {};
   vector<Some> field1;
   vector<Another> second_field;
   Widget &operator[](int i) { return { field1[i], second_field[i] }; }
};

现在您可以将小部件视为结构的常规数组:

Widgets w(5);
w[3].field1 = Some(42);

编译器擅长优化函数,但不擅长优化存储数据的方式。因此,如果您想提取一个元素或类似的元素,您可能希望operator[] 不会初始化一个新结构,而数据仍然是矢量化的。

【讨论】:

  • 我正在寻找一种方法来自动生成 operator[] 和相关样板文件,或者至少半自动生成。所以我不需要在每个类似的情况下都重做。
  • @n.m.性能提升是因为数组结构与结构数组。重载的全部目的是拥有结构数组的接口,同时仍然允许代码很好地向量化(顺便说一句,C# 会自动执行)。
  • 我正在寻找一种方法来自动获得这种过载(半或完全)。
  • @mechanical 我可以为你准备一个可变参数模板版本,但我要去睡觉了。也许明天:)
猜你喜欢
  • 1970-01-01
  • 2023-04-08
  • 2015-06-22
  • 2019-04-07
  • 1970-01-01
  • 1970-01-01
  • 2022-08-04
  • 1970-01-01
  • 2019-04-04
相关资源
最近更新 更多