Вы можете сделать это с помощью последовательностей препроцессора boost.
#define CREATE_MESSAGE(NAME, SEQ) ...
CREATE_MESSAGE(SomeMessage,
(int)(header)
(double)(temperature)
(char)(flag)
)
Вам потребуется перебирать каждую пару для генерации определений.У меня нет удобного примера кода, хотя я, возможно, смогу организовать его, если это будет интересно.
В какой-то момент у меня был генератор для чего-то подобного, который также генерировал всю сериализацию для полей.Я чувствовал, что это зашло слишком далеко.Я чувствую, что конкретные определения и декларативные посетители на полях более прямолинейны.Это немного менее волшебно, если кто-то другой должен был поддерживать код после меня.Я не знаю, какая у вас ситуация, очевидно, только после ее реализации у меня остались сомнения.:)
Было бы здорово взглянуть снова с функциями C ++ 11, хотя у меня не было шанса.
Обновление:
Есть ещенесколько изломов, чтобы работать, но это в основном работает.
#include <boost/preprocessor.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/arithmetic/mod.hpp>
#include <boost/preprocessor/control/if.hpp>
#include <tuple>
#define PRIV_CR_FIELDS(r, data, i, elem) \
BOOST_PP_IF(BOOST_PP_MOD(i, 2),elem BOOST_PP_COMMA,BOOST_PP_EMPTY)()
#define PRIV_CR_STRINGS(r, data, i, elem) \
BOOST_PP_IF(BOOST_PP_MOD(i, 2),BOOST_PP_STRINGIZE(elem) BOOST_PP_COMMA,BOOST_P
#define PRIV_CR_TYPES(r, data, i, elem) \
BOOST_PP_IF(BOOST_PP_MOD(i, 2),BOOST_PP_EMPTY,elem BOOST_PP_COMMA)()
#define CREATE_MESSAGE(NAME, SEQ) \
struct NAME { \
enum FieldID { \
BOOST_PP_SEQ_FOR_EACH_I(PRIV_CR_FIELDS, _, SEQ) \
}; \
std::tuple< \
BOOST_PP_SEQ_FOR_EACH_I(PRIV_CR_TYPES, _, SEQ) \
> data;\
template <FieldID I> \
auto get() -> decltype(std::get<I>(data)) { \
return std::get<I>(data); \
} \
template <FieldID I> \
static const char * name() { \
static constexpr char *FieldNames[] = { \
BOOST_PP_SEQ_FOR_EACH_I(PRIV_CR_STRINGS, _, SEQ) \
}; \
return FieldNames[I]; \
} \
};
CREATE_MESSAGE(foo,
(int)(a)
(float)(b)
)
#undef CREATE_MESSAGE
int main(int argc, char ** argv) {
foo f;
f.get<foo::a>() = 12;
return 0;
}
У него проблемы с getl типа decl.Я действительно не использовал кортеж, чтобы знать, чего ожидать там.Я не думаю, что это имеет какое-либо отношение к тому, как вы генерируете типы или поля.
Вот что препроцессор производит с -E:
struct foo {
enum FieldID { a , b , };
std::tuple< int , float , > data;
template <FieldID I>
auto get() -> decltype(std::get<I>(data)) {
return std::get<I>(data);
}
template <FieldID I> static const char * name() {
static constexpr char *FieldNames[] = { "a" , "b" , };
return FieldNames[I];
}
};