aantron / better-enums

C++ compile-time enum to string, iteration, in a single header file
http://aantron.github.io/better-enums
BSD 2-Clause "Simplified" License
1.65k stars 172 forks source link

attach metadata to enum values ? #51

Closed simevo closed 5 years ago

simevo commented 6 years ago

Hi, what would be your approach to attach metadata (such as descriptions, alternate representations ...) to each enum value ?

Example 1:

BETTER_ENUM(Direction, int, {
  {up, "Upwards"},
  {down, "Downwards"},
  {left, "Leftwards"},
  {right, "Rightwards"}
})
Direction d = Direction::up;
std::cout << d._meta(); // Upwards

Example 2:

BETTER_ENUM(Color, int, {
  {AliceBlue, {"#F0F8FF", 215, 223, 236}},
  {Aqua, {"#00FFFF", 0, 255, 255}}, 
  ...})
Color c = Color::Aqua;
std::cout << c._meta()[0]; // #00FFFF
aantron commented 6 years ago

Hi :)

These syntaxes do look nice, but the tricky part is how to get them parsed and output something that will get parsed by the compiler, and how to keep them optional.

Currently, Better Enums takes advantage of being able to dump the ... inside BETTER_ENUM(Foo, int, ...) directly into an enum class, so enum class {...}, and, parsing only top-level commas using the preprocessor, into an array declaration in slightly modified form, so _values = [slightly_modified(...)]. From there, the compiler takes over the parsing. You can see a simplified, but fully-working sketch in this StackOverflow answer. It focuses exactly on what Better Enums does to get the compiler to parse the declarations.

Having these inner curly braces seems like it will prevent this parsing. We could probably get them treated as initializer lists for the _values array declaration, for some type that casts to integers, but I don't think they would parse at all inside an enum class. In fact, being valid syntax for enum class is going to be the limiting factor in the current Better Enums approach, I think.

I had some ideas for using some overloaded operators to associate metadata with constants. But, the only operator that can appear to the right of an enum constant inside enum class is =, and it's not actually an operator, but another piece of syntax, in that context. So, basically, I believe we can only use =. The only way we can get to use other operators inside an enum class is by asking the user to always use =, then on the right side we get an expression, and we can ask the user to write just about anything in there. But then we lose automatic value assignment... So, I'm not sure what to do in this approach.

There may be better ways of generating the enum class than just pasting in a big, opaque token string like done now. I haven't really kept up with C++17, so perhaps there is something there :)

I recall messing around with heavier preprocessor parsing, like done by Boost, but I didn't find the results satisfactory, and I don't seem to have documented why. You're welcome to experiment with it, and I'd be happy to know the results :)

aantron commented 6 years ago

There is also this, about building bidirectional maps between a Better Enum and any types. Together with switch exhaustiveness checking, it should give you fully-checked compile-time maps. Not sure how good it is in practice, though.