X-Macros с Boost.Preprocessor?
Отбросим это от моего вопроса относительно добавления к макросам CPP:
Кто-нибудь здесь использовал типы данных библиотеки Boost.Preprocessor для реализации чего-то вроде X-макроса?
1 ответ
Я только что посмотрел, что такое X-Macro, и думаю, что сделал что-то вроде того, что вы просите.
Я хотел легко и быстро поддерживать сериализацию для серии довольно похожих классов. У меня была проблема с тем, что мне пришлось преобразовать некоторую информацию времени выполнения (int) в тип времени компиляции (класс), чтобы иметь возможность выполнять сериализацию. Я мог бы написать пару операторов case, чтобы выполнить работу, но это означало бы, что мне нужно обновлять несколько функций каждый раз, когда я хочу добавить класс.
Чтобы обойти эту проблему, я сначала определил последовательность кортежей, содержащих сопоставление:
#define WIN_MESSAGE_TYPE_SEQ \
((EM_REPLACESEL, em_replacesel))((WM_CHAR, wm_char)) //...
Имена в верхнем регистре - это определения, которые содержат int, а имена в нижнем регистре - это классы, которые я определил где-то еще.
Затем я могу использовать эту последовательность в сочетании с некоторыми препроцессорами Boost, чтобы генерировать для меня все виды кода. Например, чтобы получить предварительное объявление классов, я могу просто сделать это:
#define WIN_MESSAGE_TYPE_BUILD_MACRO(r, _data_, _elem_) \
class BOOST_PP_TUPLE_ELEM(2,1,_elem_);
BOOST_PP_SEQ_FOR_EACH(WIN_MESSAGE_TYPE_BUILD_MACRO, BOOST_PP_NIL, WIN_MESSAGE_TYPE_SEQ)
#undef WIN_MESSAGE_TYPE_BUILD_MACRO
Чтобы выполнить время выполнения для компиляции отображения времени, я генерирую серию операторов case, таких как:
#define WIN_MESSAGE_TYPE_BUILD_MACRO(r, _data_, _elem_) \
case BOOST_PP_TUPLE_ELEM(2,0,_elem_): return win_message_serializer<BOOST_PP_TUPLE_ELEM(2,1,_elem_)>::serialize(msg, o_arch);
template <typename Archive>
void serialize_win_message (p_win_message_base msg, Archive& o_arch) {
message_type_t message_type = msg->type();
switch (message_type) {
// This will generate a series of case statement for each message type that will invoke
// the serializer for the correct types.
BOOST_PP_SEQ_FOR_EACH(WIN_MESSAGE_TYPE_BUILD_MACRO, BOOST_PP_NIL, WIN_MESSAGE_TYPE_SEQ)
default: //...
};
}
#undef WIN_MESSAGE_TYPE_BUILD_MACRO
Весь код включает в себя немного больше, чем это, но это все равно должно дать вам представление о том, как генерировать код с использованием препроцессоров Boost. В моем примере я могу быстро и легко добавить поддержку сериализации для класса, просто обновив свою последовательность.
Обратите внимание, что использование препроцессора Boost не дает очень читабельный код, поэтому я стараюсь максимально упростить макрос, используемый для каждого макроса. Также я не удивлюсь, если у кого-то есть более элегантное решение этой проблемы. Это как раз то, что я придумал для личного проекта, где я не против дополнительной сложности.