Olumide
Olumide

Reputation: 5809

Creating an array of strings from preprocessor tokens

I've got a list of tokens from which I'd like to create an enum (trivial) and an array of strings (to be later used to create a map of string to enum). Here's my attempt:

#define TOKEN_LIST  CUBE , SPHERE , CIRCLE
#define CREATE_ARRAY_OF_STRINGS( ... )  const char* token[] = { __VA_ARGS__ };  

CREATE_ARRAY_OF_STRINGS( TOKEN_LIST )
// enum SHAPE_TYPE{ TOKEN_LIST }; // easy

int main(int argc, char *argv[])
{
    return 1;
}

The problem is that the TOKEN_LIST is not stringified as shown when I compile with the -E flag as follows:

const char* token[] = { CUBE , SPHERE , CIRCLE };

int main(int argc, char *argv[])
{
    return 1;
}

Where const char* token[] = { CUBE , SPHERE , CIRCLE }; should be const char* token[] = { "CUBE" , "SPHERE" , "CIRCLE" };

Is there any other way to achieve this with C++03? Boost Processor perhaps?

Upvotes: 2

Views: 1209

Answers (1)

If you're willing to change the format of your TOKEN_LIST somewhat, you can easily do this with Boost.Preprocessor.

Here's an example of using a Boost.Preprocessor sequence instead of a comma-separated list:

#define GENERATE_STRING(maZ, maIdx, maTokens) \
  BOOST_PP_STRINGIZE(BOOST_PP_SEQ_ELEM(maIdx, maTokens))

#define GENERATE_STRINGS(maTokens) \
  BOOST_PP_ENUM(BOOST_PP_SEQ_SIZE(maTokens), GENERATE_STRING, maTokens)

#define TOKEN_LIST (CUBE)(SPHERE)(CIRCLE)

const char* token[] = { GENERATE_STRINGS(TOKEN_LIST) }

enum ShapeType {
  BOOST_PP_SEQ_ENUM(TOKEN_LIST)
};

Since you seem to have access to ... and __VA_ARGS__ (which are not a C++03 feature), you should be able to use a Boost.Preprocessor tuple as well (comma-delimited list enclosed in parentheses); with support for variadic macros, Boost.Preprocessor is capable of determining tuple size implicitly. However, I have no experience with that, so I cannot provide a code example.


The maZ argument is an implementation feature of Boost.Preprocessor repetition macros. There are three: z (used by enum-style functions), d (used by while-style functions), and r (used by for-style functions). It is only useful when nesting these contructs, as it allows faster preprocessing. If GENERATE_STRING was itself calling an enum function, then using BOOST_PP_ENUM_ ## maZ would be easier on the preprocessor than just using BOOST_PP_ENUM for the nested invocation (but the latter works as well, as long as you don't exceed the compiler's preprocessing limits).

Upvotes: 2

Related Questions