Я ищу способ получения смещений членов данных класса C ++, который имеет не-POD характер.
И вот почему:
Я хотел бы хранить данные в формате HDF5 , который кажется наиболее подходящим для моего вида материала (вывод числового моделирования), но, возможно, это довольно ориентированная на C библиотека. Я хочу использовать его через интерфейс C ++, что потребует от меня объявления типов хранения следующим образом (следуя документации здесь и здесь (раздел 4.3.2.1.1)):
class example {
public:
double member_a;
int member_b;
} //class example
H5::CompType func_that_creates_example_CompType() {
H5::CompType ct;
ct.insertMember("a", HOFFSET(example, member_a), H5::PredType::NATIVE_DOUBLE);
ct.insertMember("b", HOFFSET(example, member_b), H5::PredType::NATIVE_INT);
return ct;
} //func_that_creates_example_CompType
где HOFFSET - специфичный для HDF макрос, который использует offsetof.
Проблема, конечно, в том, что, как только пример класса становится немного более функциональным, он перестает быть POD-типом, и поэтому использование offsetof даст неопределенные результаты.
Единственный обходной путь, о котором я могу подумать - это сначала экспортировать данные, которые я хочу сохранить, в более простую структуру, а затем передать их в HDF. Это, однако, включает в себя копирование данных, чего именно HDF пытается избежать (и почему у них есть этот CompType, который позволяет библиотеке обращаться к вашим объектам, чтобы сохранить свои данные в файл).
Так что я надеялся, что у вас будут лучшие идеи. В идеале я бы искал переносное решение этой проблемы, но если бы не это, вы могли бы дать мне идею, которая работает на x86 и x86_64 с GCC, я уже был бы безмерно благодарен.
----- добавлено позже: -----
Грег Хьюгилл предложил ниже сохранить данные в простой структуре, а затем построить реальный класс, унаследовав его от этого. Что касается HDF, я думаю, что это может не сработать. Более сложный сценарий использования, чем выше:
class base_pod {
public:
double member_a;
int member_b;
}; //class base_pod
class derived_non_pod : private base_pod {
public:
//the following method is only virtual to illustrate the problem
virtual double get_member_a() {return member_a; }
}; //class derived_non_pod
class that_uses_derived_non_pod {
public:
void whatever();
private:
derived_non_pod member_c;
}; //class that_uses_derived_non_pod
Теперь, когда мы храним экземпляры класса that_uses_derived_non_pod, мы не можем описать макет его памяти, как если бы он имел base_pod как member_c. Это может привести к неправильному смещению, потому что output_non_pod добавляет интересные вещи (например, таблицу виртуальных функций, я полагаю?).