I have a struct Widget
which has several fields inside:
struct Widget
{
Some field1;
Another second_field;
...
};
Conceptually I need an array or vector of these Widgets, i.e. std::vector<Widget>
. But for performance reasons all those fields should be in it's own array, i.e.:
struct Widgets
{
vector<Some> field1;
vector<Another> second_field;
...
};
So, given that Widget
what are possible approaches in C++ to scatter it's fields on several vectors, i.e. to convert array of structures to struct of arrays of fields? Manual definition of some reasonable metadata is OK (inside or outside Widget
), but solution without additional metadata is preferred.
To clarify, I am looking for a automatic or semi-automatic way of converting Widget
struct to Widgets
struct, without manually coding all boilerplate glue.
The core functionality can be implemented using std::transform
and a few lambda functions.
To get a std::vector<Some>
from a std::vector<Widget>
, use:
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; });
I'll let you figure out the rest.
I am looking for a automatic or semi-automatic way of converting
Widget
struct toWidgets
struct, without manually coding all boilerplate glue.
You will have to write some boilerplate code for each member variable of Widget
. You will be able to reduce the amount of boiler plate code a bit by using a helper function of your own.
E.g.
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);
}
and use it as:
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; });
...
You could overload the []
operator so that the members adjacent in memory (as the second example) but you can behave as if there was a vector of structs:
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] }; }
};
Now you can treat Widgets as a regular array of structs:
Widgets w(5);
w[3].field1 = Some(42);
The compiler is good at optimizing functions but not the way you store data. Thus you may expect operator[]
not to initialize a new struct if you want to extract an element or similar, while the data are still vectorized.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With