I have a struct
with some other struct
s as member. Both external and internal structs are StandardLayout
(it can be even assumed that internal are plain old data). Something like this:
struct Inner1 {
int a = 0, b = 0;
};
struct Inner2 {
int c = 0, d = 0;
};
struct Outer {
Inner1 x;
std::string s;
Inner2 y;
};
I want to write some function that takes Outer&
and object of some type T
that can return value of any nested field, depending on argument:
int get(Outer& o, T field);
If Outer
was a flat structure, pointers to member would be exactly what I needed, however it is not flat.
The trivial way is to make T
a enum
of all fields and write a switch
, but I it it not efficient. The faster way is to make T
an offset and write
int get(Outer& o, size_t field) {
return *reinterpret_cast<int*>(reinterpret_cast<char*>(o) + field);
}
and then call it like get(o, offsetof(Outer, y) + offsetof(Inner2, c))
. It works, but I am not sure if it is guaranteed to work - if it is correct to sum offsets like this and if it is safe to take member value by offset.
So, the question: is this way safe? If not, is there a safe way? Constructing values of T
can be arbitrary complex, however using them should be fast.
Motivation: I will need to put values from some of nested fields in some order, known at startup, but not in compile time. I wanted to create an array of T
at startup and then, when getting particular object, use this precalced array.
[UPD]: So it will be used like this:
void bar(int);
void foo(Outer& o, vector<T>& fields) {
for (auto& field : fields) {
bar(get(o, field));
}
}