Скомпилировать время сгенерированного блока в C ++

У меня есть структура на моем сервере, которую я хотел бы сгенерировать с помощью макроса или шаблона на C ++, поскольку у него много избыточных вещей:

struct MyBlock { void Merge(const MyBlock& from) { if (apple.HasData()) { apple.Merge(from.apple); } if (banana.HasData()) { banana.Merge(from.banana()); } ... } void Clear() { apple.Clear(); banana.Clear(); ... } void Update(const SimpleBlock& simple_block) { if (simple_block.apple.Updated()) { apple.Add(simple_block.apple); } if (simple_block.banana.Updated()) { banana.Add(simple_block.banana); } ... } Fruit apple; Fruit banana; Animal dog; Animal cat; ... } struct SimpleBlock { SimpleFruit apple; SimpleFruit banana; SimpleAnimal dog; SimpleAnimal cat; ...; } 

Я хотел бы определить больше переменных в двух блоках, таких как яблоко и собака. Я также хотел бы определить больше пар таких блоков. Но это связано с большим количеством тривиальной работы. Итак, мой вопрос заключается в том, как мы можем использовать макрос, шаблон или некоторые другие возможности C ++, включая C ++ 11, для генерации этих блоков во время компиляции?

Причина, по которой я не использую коллекции для хранения этих переменных, заключается в том, что структура MyBlock будет передана как параметр в другом classе шаблонов, который будет динамически распределять и освобождать этот блок во время выполнения. Это фактически локальный блок streamа, который будет агрегироваться периодически.

Достаточно ровно с итерацией списка препроцессоров:

 #define M_NARGS(...) M_NARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) #define M_NARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N #define M_CONC(A, B) M_CONC_(A, B) #define M_CONC_(A, B) A##B #define M_ID(...) __VA_ARGS__ #define M_LEFT(L, R) L #define M_RIGHT(L, R) R #define M_FOR_EACH(ACTN, ...) M_CONC(M_FOR_EACH_, M_NARGS(__VA_ARGS__)) (ACTN, __VA_ARGS__) #define M_FOR_EACH_0(ACTN, E) E #define M_FOR_EACH_1(ACTN, E) ACTN(E) #define M_FOR_EACH_2(ACTN, E, ...) ACTN(E) M_FOR_EACH_1(ACTN, __VA_ARGS__) #define M_FOR_EACH_3(ACTN, E, ...) ACTN(E) M_FOR_EACH_2(ACTN, __VA_ARGS__) #define M_FOR_EACH_4(ACTN, E, ...) ACTN(E) M_FOR_EACH_3(ACTN, __VA_ARGS__) #define M_FOR_EACH_5(ACTN, E, ...) ACTN(E) M_FOR_EACH_4(ACTN, __VA_ARGS__) //.. extend this to higher numbers with some copy&paste #define MYBLOCK(...) struct MyBlock { \ void Merge(const MyBlock& from) { \ M_FOR_EACH(BLOCK_MERGE, __VA_ARGS__) \ } \ void Clear() { \ M_FOR_EACH(BLOCK_CLEAR, __VA_ARGS__) \ } \ void Update(const SimpleBlock& simple_block) { \ M_FOR_EACH(BLOCK_UPDATE, __VA_ARGS__) \ } \ M_FOR_EACH(BLOCK_FIELD, __VA_ARGS__) \ } #define BLOCK_MERGE(F) if (M_ID(M_RIGHT F).HasData()) { \ M_ID(M_RIGHT F).Merge(from.M_ID(M_RIGHT F)); \ } #define BLOCK_CLEAR(F) M_ID(M_RIGHT F).Clear; #define BLOCK_UPDATE(F) if (simple_block.M_ID(M_RIGHT F).Updated()) { \ M_ID(M_RIGHT F).Add(simple_block.M_ID(M_RIGHT F)); \ } #define BLOCK_FIELD(F) M_ID(M_LEFT F) M_ID(M_RIGHT F); #define SIMPLEBLOCK(...) struct SimpleBlock { M_FOR_EACH(SIMPLE_DECL, __VA_ARGS__) } #define SIMPLE_DECL(F) M_CONC(Simple, M_ID(M_LEFT F)) M_ID(M_RIGHT F); #define FIELDS (Fruit, apple),(Fruit,banana),(Animal,dog),(Animal,cat) MYBLOCK(FIELDS); SIMPLEBLOCK(FIELDS); 

Добавьте необходимые дополнительные переменные-члены в FIELDS в существующий формат, и они будут добавлены в структуры, выпущенные MYBLOCK и SIMPLEBLOCK . (Не забудьте расширить M_FOR_EACH с большим количеством итераций … легко с помощью нескольких ctrl + c, ctrl + v.)

 template  class BlockTemplate { public: void Merge(const BlockTemplate& from) { if (HasData()) { Merge(from.simpleData); } } void Update(const SimpleT& simple_block) { if (simple_block.Updated()) { Add(simple_block.data); } } protected: SimpleT simpleData; }; 

Теперь вы можете создавать объекты типа BlockTemplate , BlockTemplate и т. Д. Вы также можете хранить указатели на все эти объекты BlockTemplate в контейнере после того, как BlockTemplate наследуется от абстрактного типа. Или, еще лучше, используйте новые методы стирания boost::type_erasure::anyboost::type_erasure::any например.

EDIT: Если вы не хотите использовать контейнер таким образом, вы также можете сделать BlockTemplate variadic и сохранить кортеж из разных (по типу) объектов SimpleT и соответственно изменить функции Merge и Update . Проблема заключается в том, что значительно сложнее отслеживать объекты SimpleTstd::tuple не позволяет вам SimpleT имена. Вы будете ссылаться на значения как get(tupleData) .

Описание того, почему вы не используете коллекцию, похоже на некоторую оптимизацию. Вы измерили?

Во всяком случае, одним простым решением являются указатели на хранилище объектов в коллекции.

Затем вы можете перебирать коллекцию.