2

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?

2
  • Why you need this? If you use macro, that means you know before the code starts executing. So you can store them in variables instead. And use to create array or directly use them in array initialization. Commented Jan 15, 2016 at 15:38
  • In order to automatically update a map of strings to enums. I'd like to register tokens at just one point and automatically update the enum list and map. But this is not the part that I need help with. Commented Jan 15, 2016 at 15:41

1 Answer 1

2

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).

Sign up to request clarification or add additional context in comments.

4 Comments

What role does maZ play in GENERATE_STRING( )?
@Olumide Answer expanded.
Thanks. Is there a reason why all the arguments begin with ma? Also does the case of z matter. I'm asking because you've used different cases in your code and explanation .
@Olumide The case (and spelling) doesn't matter at all, they're macro arguments like any other. ma is just my personal coding style for prefixing macro arguments.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.