У меня есть struct
с некоторыми другими struct
участниками. И внешняя, и внутренняя структуры - StandardLayout
(можно даже предположить, что внутренние - это просто старые данные). Примерно так:
struct Inner1 {
int a = 0, b = 0;
};
struct Inner2 {
int c = 0, d = 0;
};
struct Outer {
Inner1 x;
std::string s;
Inner2 y;
};
Я хочу написать некоторую функцию, которая принимает Outer&
и объект некоторого типа T
, который может возвращать значение любого вложенного поля, в зависимости от аргумента:
int get(Outer& o, T field);
Если бы Outer
была плоской структурой, указатели на член были бы именно тем, что мне нужно, но это не плоская
Тривиальный способ - сделать T
а enum
всего поля и напишите switch
, но я это не дееспособный. Более быстрый способ - сделать T
смещением и написать
int get(Outer& o, size_t field) {
return *reinterpret_cast<int*>(reinterpret_cast<char*>(o) + field);
}
, а затем назвать его как get(o, offsetof(Outer, y) + offsetof(Inner2, c))
. Это работает, но я не уверен, что это сработает гарантированно - правильно ли суммировать подобные смещения и безопасно ли брать значение члена по смещению.
Итак, вопрос: вот так сейф? Если нет, есть ли безопасный способ? Создание значений T
может быть произвольным сложным, однако их использование должно быть быстрым.
Мотивация: мне нужно будет поместить значения из некоторых вложенных полей в некотором порядке, известном при запуске, но не во время компиляции . Я хотел создать массив T
при запуске, а затем, при получении определенного объекта, использовать этот предварительно вычисленный массив.
[UPD]: Итак, он будет использоваться следующим образом:
void bar(int);
void foo(Outer& o, vector<T>& fields) {
for (auto& field : fields) {
bar(get(o, field));
}
}