Сбор списка функций, которые впоследствии следует вызывать в макросах - PullRequest
2 голосов
/ 19 января 2012

Я пишу небольшую библиотеку, с которой перечисления в C ++ должны стать проще.Синтаксис выглядит примерно так:

ENUM_START(MyEnum)
    ENUM_VAL(Val1)
    ENUM_VAL(Val2)
    ...
ENUM_END

Эти макросы создают класс MyEnum с, например, следующим доступом:

MyEnum bla=MyEnum::Val1;
for(MyEnum::iterator iter=MyEnum::begin();iter!=MyEnum::end();++iter)
    cout << iter->toString();

и несколькими дополнительными функциями, такими как хранение дополнительных данных (например,строки) для перечисления значений.

Макросы завершены и работают, но их не так просто определить, как показано выше.Для этого мне нужен способ создать список функций инициализатора с макросами ENUM_VAL, которые я позже смогу вызвать.Что-то вроде следующего подхода boost :: mpl:

typedef mpl::vector<> list__COUNTER__;
#define ENUM_VAL(Name)                                                         \
    ...                                                                        \
    struct Init##Name{void init() {initialization code}};                      \
    typedef mpl::push_back<                                                    \
        list##(__COUNTER-1),                                                   \
        Init##Name                                                             \
      >::type list##__COUNTER__;                                               \

Этот список путей ## (__ COUNTER __- 1) в конце содержит тип Init ## Name, и я могу в конце вызвать init () навсе хранимые типы с использованием mpl foreach.

Теперь проблема заключается в присвоении имен.Я должен использовать __COUNTER__ дважды для каждого экземпляра макроса, который увеличивает счетчик в два раза.Я уже искал и обнаружил, что

  • Препроцессор C не вычисляет (__COUNTER __- 1) при именовании переменных
  • нет способа прочитать __COUNTER__, не увеличивая его.

Поэтому мне нужен другой способ собрать список функций, которые я позже смогу вызвать.

Ответы [ 2 ]

2 голосов
/ 19 января 2012

Вы можете использовать Boost.Preprocessor и, в частности, это последовательностей . Это приведет к использованию макроса, похожему на это:

MAKE_ENUM(MyEnum, (Val1)(Val2)(Val3))

Используя SEQ_ENUM, SEQ_FOR_EACH_I и др., Вы можете создать код относительно просто.

Был также предложен Boost.Enum , который уже может удовлетворить ваши потребности.

1 голос
/ 19 января 2012

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

Недостатком является добавление еще одного требования к инструменту, если кто-то хочет что-то изменить.

Я использовал для этого Гепард , и я не разочаровался в результате.

...