1

I have a const static std::map and I want to fill it with the preprocessor. I want a mapping between my enumeration and string-names of the enum type. For example:

enum Color {
  RED,
  BLUE,
  GREEN
};

const static std::map<std::string, Color> = {
  {"RED", Color::RED},
  {"red", Color::RED},
  {"BLUE", Color::BLUE},
  {"blue", Color::BLUE},
  {"GREEN", Color::GREEN}
  {"green", Color::GREEN}
};

That is a simple example. I want to write something like:

enum Color {
  RED,
  BLUE,
  GREEN
};

const static std::map<std::string, Color> = {
  CREATE(RED),
  CREATE(BLUE),
  CREATE(GREEN)
};

I have lots of values in my enumeration and you see that it is a lot of work, even for a few values. I thought about using some preprocessor magic but I don't know how to get it working. My first thought was:

#define(name) {"name", Color::name}

My second thought was:

#define(name) {"(name)", Color::(name)}

In the first case I get the string "name" as the key, in the second case I get the string "(name)" as the key and a compiler error because of my value. It would be great to get a solution for this problem, even if this would not include a lower-case version of the string. That would just be a small bonus. Do you have any ideas how I could solve my problem?

edit: Thank's to @Gem Taylor. I have a solution for the first problem:

#define CREATE(name) {#name, Color::name}

If you have an idea how to create the version with the lowercase string, that would be great. So that:

CREATE(RED)

would create:

{"RED", Color::RED}, {"red", Color::RED}

Thank's

Schorsch
  • 319
  • 1
  • 14
  • Look up the preprocessor stringising operator. –  Jun 01 '18 at 16:53
  • 2
    See the ["stringification" operator (`#`)](http://en.cppreference.com/w/cpp/preprocessor/replace). – François Andrieux Jun 01 '18 at 16:53
  • for this case, it seems a good case for a case-insensitive comparator for your map. Alternatively, instead of `set`, call a method that generates and adds the lower case version, too. – peterchen Jun 01 '18 at 17:51

1 Answers1

2

There is a special stringifier feature in macros #, and also token concatenation ## :

#define CREATE(name) {#name, Color::name}

See the gcc docs - this is a standard feature of C.

Gem Taylor
  • 5,381
  • 1
  • 9
  • 27
  • 2
    To be clear, this isn't a gcc feature. It's a [standard feature](http://en.cppreference.com/w/cpp/preprocessor/replace). – François Andrieux Jun 01 '18 at 16:56
  • Thanks. That works perfect. Do you have a clue how a could also insert a lower case version of my string? – Schorsch Jun 01 '18 at 16:58
  • You have to call function for that (or similar). – Jarod42 Jun 01 '18 at 17:02
  • Alternatively, if you used const char pointers and wrote your own map comparator that used stricmp then you could avoid doing the to-lower conversion. – Gem Taylor Jun 01 '18 at 18:00
  • @GemTaylor: No need to switch to const char pointer to customize the comparer. – Jarod42 Jun 01 '18 at 22:02
  • Thought that there is maybe some compile-time solution. But yes, there are some workarounds i could use. – Schorsch Jun 02 '18 at 07:08
  • @Jarod42 - indeed, you can do case ignore compares on std::string, but you still have to resort to "C" methods, and .c_str(). If the input strings are compile-time C constants, I would use them directly and cut out the "middle man". Note that stricmp is generally slower than strcmp. You could also consider an unordered_map, but then need to write a case-ignoring hash function. – Gem Taylor Jun 04 '18 at 09:56
  • @Schorsch If you only want to accept a capitalised input, then the custom mapping or hash function removes the capitalisation from the check and you don't need to duplicate them. If you actually want to offer these names in some UI feature, you wouldn't want to duplicate them anyway. – Gem Taylor Jun 04 '18 at 10:47
  • @GemTaylor it was a 'feature' i don't need anymore. I need it for mapping between some input identifiers and my own enumeration-type. In my case it is clearer to only accept one spelling for identifiers. – Schorsch Jun 04 '18 at 11:46