Search code examples
c++c-preprocessormetaprogrammingtemplate-meta-programmingboost-mpl

Collecting a list of functions that later should be called in macros


I am writing a small library with which enums in C++ should get easier. The syntax is something like:

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

This macros create a class MyEnum with allows for example the following access:

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

and a few more features like storing additional data (for example strings) to enum values.

The macros are finished and work, but are not as easy to define as shown above. For this I need a way to create a list of initializer functions with the ENUM_VAL macros that I later can call. Something like the following boost::mpl approach:

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__;                                               \

This way list##(__COUNTER__-1) contains in the end the type Init##Name and I can in the end call init() on all stored types using mpl foreach.

The problem now is the naming. I have to use __COUNTER__ twice per macro instantiation, which increments the counter twice. I already searched and found out that

  • The C preprocessor doesn't calculate (__COUNTER__-1) when naming the variables
  • there is no way to read __COUNTER__ without incrementing it.

So I need another way to collect a list of functions I later can call.


Solution

  • You could use Boost.Preprocessor and specifically it's sequences. This would result in a macro-usage similar to this:

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

    Using SEQ_ENUM, SEQ_FOR_EACH_I et al, you can then generate the code relatively easy.

    There was also a proposed Boost.Enum which might suit your needs already.