Adventure >>
let's run..

C++ enumerate


Mapping enumerate value to a string

In C, normally when you want to map a enumerate value to a string, to print it, we can implement like this.

typedef enum {
  none = 0,
  pass,
  fail
} enVerdictValueType;
const char *VERDICT_STR[] = {
  [none] = "NONE",
  [pass] = "PASS",
  [fail] = "FAIL"
}
void func(enVerdictValueType val)
{
  // because of enum type, some time we could push int value to variable "val"

  // incase of val receive from other source, it could cause out of array access if we don't check it carefully

  printf("VERDICT: %s\r\n", VERDICT_STR[val]);
}

Let try to improve above print enum implementation in C++.

#include <vector>

// create a general class that will do the enumerate mapping with string and do the checking

class EnumMap
{
private:
    // vector to store the const string for enum map

    std::vector<const char*> table;
    // string to print when input enum value is out of index range

    const char* ERROR_STRING = "OUT_OF_RANGE";
public:
    // && is rvalue reference, specify rvalue because we initialize

    // the string vector table with rvalue

    EnumMap(std::vector<const char*>&& input_table)
      : table(std::move(input_table)) {}
    ~EnumMap() {}
    // override the operator []

    const char* operator[](ssize_t idx) const
    {
        // index checking

        if ((idx < 0) || ((size_t)idx > table.size()))
        {
            // return ERROR string incase of input value is not exist in enum type

            return ERROR_STRING;
        }
        else
        {
            // return corresponding string

            return table[idx];
        }
    }
};

// here is the part we using

// create enum

typedef enum {
  none = 0,
  pass,
  fail
} enVerdictValueType;
// create corresponding enum string map with easier syntax

const EnumMap VERDICT_STR({"NONE", "PASS", "FAIL"});
// use it

>> std::cout << VERDICT_STR[pass] << std::endl;

How about when you have a enumerate with its value does not span continuously, We could modify the EnumMap to use std::unordered_map<int, std::string> instead of std::vector

#include <unordered_map>


typedef enum {
  none = 0,
  pass = 22,  // << weird, but could happen

  fail = 12
} enVerdictValueType;
const EnumMap VERDICT_STR({
  {none, "NONE"}, // << have to provide the index corresponding with string

  {pass, "PASS"},
  {fail, "FAIL"}});

class EnumMap
{
private:
    // unordered_map to store the const string for enum map

    std::unordered_map<int, const char*> table;
    // string to print when input enum value is not existed

    const char* ERROR_STRING = "OUT_OF_RANGE";
public:
    // && is rvalue reference, specify rvalue because we initialize

    // the string vector table with rvalue

    EnumMap(std::unordered_map<int, const char*>&& input_table)
      : table(std::move(input_table)) {}
    ~EnumMap() {}
    // override the operator []

    const char* operator[](ssize_t idx) const
    {
        // index checking

        if (0 == table.count(idx))
        {
            // return ERROR string incase of input value is not exist in enum type

            return ERROR_STRING;
        }
        else
        {
            // return corresponding string

            return table.at(idx);
        }
    }
};

Above class implementation help us initialize enumerate string map easier and less error-prone.