0

I use something like in the following code fairly often:

// myclass.h

class MyClass {
 public:
  enum MyEnum { E1, E2, NUMMYENUM };
  const char* kMyEnum[NUMMYENUM] = {"e1", "e2"};
  const char* MyEnum2Char(MyEnum me) { return kMyEnum[me]; }

  enum MySEnum { SE1, SE2, NUMMYSENUM };
  static const char* kMySEnum[NUMMYSENUM];
  static const char* MySEnum2Char(MySEnum se) { return kMySEnum[se]; }

  void foo(MyEnum me) {
    //do something, e.g. print
    std::cout << MyEnum2Char(me) << "maps to " << emap[me] << "\n";
  }

  void bar(MySEnum se) {
    //do something, e.g. print
    std::cout << MySEnum2Char(se) << "maps to " << semap[se] << "\n";
  }

 private:
  std::map<MyEnum, int> emap;
  std::map<MySEnum, int> semap;
 };


// myclass.cc

#include "myclass.h"

const char* MyClass::kMySEnum[MyClass::MySEnum::NUMMYSENUM] = {"se1", "se2"};

The way of generating an enum, a char* array and a function converting enum to char seems to add avoidable clutter and I am wondering if there isn't another way to achieve this? Something like the following isn't possible for multiple reasons, but might give you an idea of what I'd like to have:

// myclass.h

class MyClass {
 public:
  MyVariableEnumClass MyEnum(E1, "e1", E2, "e2");    
  static MyVariableEnumClass MySEnum;

  void foo(MyEnum me) {
    //do something, e.g. print
    std::cout << me.string() << "maps to " << emap[me] << "\n";
  }

  void bar(MySEnum se) {
    //do something, e.g. print
    std::cout << se.string() << "maps to " << semap[se] << "\n";
  }

 private:
  std::map<MyEnum, int> emap;
  std::map<MySEnum, int> semap;
 };


// myclass.cc

#include "myclass.h"

MyVariableEnumClass MyClass::MySEnum = MyVariableEnumClass(SE1, "se1", SE2, "se2");

Is there a way to achieve something 'clutter-free' like this? Maybe using macros?

underscore_d
  • 6,309
  • 3
  • 38
  • 64
SemtexB
  • 660
  • 6
  • 21
  • Does this answer your question? [enum to string in modern C++11 / C++14 / C++17 and future C++20](https://stackoverflow.com/questions/28828957/enum-to-string-in-modern-c11-c14-c17-and-future-c20) – underscore_d Oct 01 '20 at 08:49
  • Kind of, I think. The drawbacks are that it needs c++17, whereas I'm using c++11 and additionally I'd like to specify (with possibly different naming) the char/string attached to each enum (`E1` and `"e1"`), while `magic_enum` seems to have the same naming for both (`E1` and `"E1"`). – SemtexB Oct 01 '20 at 10:38
  • One trick used sometimes is to have a header file defining enum values, something like this: `ENUM_VALUE(SE1, "se1")` (more like this). The file itself doesn't define `ENUM_VALUE`. Then you #include this header twice - once defining `ENUM_VALUE` in a way that emits, well, enum values, and again defining it to emit string literals. So you can generate `MyEnum` and `kMyEnum` off the same source. – Igor Tandetnik Oct 03 '20 at 22:52
  • Another trick is to define the data in a scripting language of one's choice, and write a script to automatically generate C++ code off that. – Igor Tandetnik Oct 03 '20 at 22:53

1 Answers1

0

A technique called XMacro can be used in C++ 11 as well as older versions of C++ and C to easily define consistent look-up tables for translating enums to strings.

First, you write an external file (let's call it my_class.xmacro) which includes the following:

#define SE_ENUM_TABLE  \
    ENTRY(SE1) \
    ENTRY(SE2) 

Next in your H file you include my_class.xmacro define the following:

#include "my_class.xmacro"

    
enum SeEnum{
#define ENTRY(a) a,
       SE_ENUM_TABLE
#undef ENTRY
    };

const std::string seEnumString[] = {
#define str_macro(a) #a
#define ENTRY(a) str_macro(a),
    SE_ENUM_TABLE
#undef ENTRY
};

The macros inside seEnumStringId take ENTRY(a) and transform it to "a". So after pre-processor is finished with this file, it actually looks to the compiler as follows:

enum SeEnum{
    SE1,
    SE2 
};
    
const std::string seEnumString[] = {
    "SE1",
    "SE2" 
    };

Using this technique you ensure that adding an enum will automatically create string id in the RIGHT order, and this technique can be used to generate additional types of look-up tables as well.

Yitshak Yarom
  • 84
  • 1
  • 4