X-Macros с Boost.Preprocessor?

Отделив это от моего вопроса о добавлении к макросам CPP:

Кто-нибудь здесь использовал типы данных библиотеки Boost.Preprocessor для реализации чего-то вроде X-macro?


person J. C. Salomon    schedule 29.12.2010    source источник


Ответы (1)


Я только что посмотрел, каким должен быть X-Macro, и я думаю, что сделал что-то вроде того, о чем вы просите.

Что я хотел сделать, так это легко и быстро поддерживать сериализацию для ряда довольно похожих классов. Проблема, с которой я столкнулся, заключалась в том, что мне пришлось преобразовать некоторую информацию времени выполнения (int) в тип времени компиляции (класс), чтобы иметь возможность выполнять сериализацию. Я мог бы написать пару операторов case, чтобы выполнить эту работу, но это означало бы, что мне придется обновлять несколько функций каждый раз, когда я хочу добавить класс.

Чтобы обойти эту проблему, я сначала определил последовательность из кортежей, содержащих сопоставление:

#define WIN_MESSAGE_TYPE_SEQ \
    ((EM_REPLACESEL, em_replacesel))((WM_CHAR, wm_char)) //...

Имена в верхнем регистре — это определения, которые содержат целое число, а имена в нижнем регистре — это классы, которые я определил где-то еще.

Затем я могу использовать эту последовательность в сочетании с некоторыми из 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 не дает очень читаемого кода, поэтому я стараюсь, чтобы макрос, используемый для каждого макроса, был как можно более простым. Также я не удивлюсь, если у кого-то есть более элегантное решение этой проблемы. Это как раз то, что я придумал для личного проекта, где я не против дополнительной сложности.

person Ze Blob    schedule 29.12.2010