X-Macros с Boost.Preprocessor? - PullRequest
       21

X-Macros с Boost.Preprocessor?

2 голосов
/ 29 декабря 2010

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

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

1 Ответ

3 голосов
/ 29 декабря 2010

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

...