Enum to string: возвращает значение целочисленного числа enum, если оно недействительно/не найдено.

Итак, я применил функцию enumToString для нескольких перечислений, которые я использую много (часто спрашивается в SO: Есть ли простой способ преобразования С++ enum в строку?, Простой способ использовать переменные типов перечисления как строку в C?,...). Это облегчает отладку сообщений об ошибках WAY, но я должен поддерживать функцию для добавления значений, которые иногда не содержат описания строк.

Мой код выглядит следующим образом:

typedef std::map<my_enum_e, const char *> enum_map_t;
static bool s_enum_map_initialized = false;

static enum_map_t s_enum_strings;

static void s_init_maps()
{
#define ADD_ENUM( X ) s_enum_strings[X] = #X;

    if( s_enum_strings.size() == 0)
    {
        ADD_CLASS( MY_ENUM_1 );
        ADD_CLASS( MY_ENUM_2 );
        /* ... all enums */
    }
    s_enum_map_initialized = true;
}

const char *Tools::enumCString( my_enum_e e )
{
    if( ! s_enum_map_initialized )
    {
        s_init_maps();
    }

    // todo: use the iterator instead of searching twice
    if( s_enum_strings.find(e) != s_enum_strings.end() )
    {
        return s_class_strings[e];
    }

    return "(unknown enum_e)";
}

Теперь, что я хочу, это то, что, когда я не нахожу enum на карте, верните "(unknown enum %d)", e. Который даст мне значение перечисления, которое я пропустил.

Таким образом, даже если я не добавил его к карте, у меня все еще есть его значение, и я могу отлаживать свою программу.

Я не могу найти способ сделать это просто: строковый поток, созданный в стеке, будет уничтожен сразу после возврата, строковый поток static не является потокобезопасным,...

изменить: конечно, использование типа std::string в качестве возвращаемого типа позволит мне форматировать его, но я часто вызываю эти функции в своем коде, я полагал, что передача указателя const char * быстрее, так как мне не нужно каждый раз нажимать std::string на стек.

Любое решение?

Ответ 1

Верните a std::string, а не char*.

Это позволит вам использовать std::stringstream для генерации вашего сообщения. Затем вызывающему сайту просто нужно будет использовать функцию члена .c_str( ) на std::string, чтобы получить указатель на C-стиль (если требуется).

Ответ 2

Лично я использую BOOST:)

Пример использования:

SANDBOX_DEFINE_ENUM(MyEnum, (Foo)(Bar)(Team))

Уступит:

struct MyEnum {
  enum Type {
    Foo,
    Bar,
    Team
  };
  static Type const First = Foo;
  static Type const Last = Team;
};

inline char const* toString(MyEnum::Type value) {
  switch(value) {
  case MyEnum::Foo: return "Foo";
  case MyEnum::Bar: return "Bar";
  case MyEnum::Team: return "Team";
  }
  return 0;
}

код:

#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/stringize.hpp>

#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/reverse.hpp>
#include <boost/preprocessor/seq/seq.hpp>

#define SANDBOX_DEFINE_ENUM(Name_, Values_)                                     \
  SANDBOX_DEFINE_ENUM_TYPE(Name_, Values_)                                      \
  SANDBOX_DEFINE_ENUM_STRING(Name_, Values_)

#define SANDBOX_DEFINE_ENUM_TYPE(Name_, Values_)                                \
  struct Name_ {                                                                \
    enum Type {                                                                 \
      BOOST_PP_SEQ_ENUM(Values_)                                                \
    };                                                                          \
    static Type const First = BOOST_PP_SEQ_HEAD(Values_);                       \
    static Type const Last = BOOST_PP_SEQ_HEAD(BOOST_PP_SEQ_REVERSE(Values_));  \
  };

#define SANDBOX_DEFINE_ENUM_STRING(Name_, Values_)                              \
  inline char const* toString(Name_::Type value) {                              \
    switch(value) {                                                             \
      BOOST_PP_SEQ_FOR_EACH(SANDBOX_DEFINE_ENUM_TO_STRING_C, Name_, Values_)    \
    }                                                                           \
    return 0;                                              \
  }

#define SANDBOX_DEFINE_ENUM_TO_STRING_C(r, Name_, Elem_)                        \
  case Name_::Elem_: return BOOST_PP_STRINGIZE(Elem_);

Очевидно, что он работает только с "регулярными" перечислениями, а не с выполненными на заказ. Но поскольку он определен в одном месте в коде... нет штрафа за обслуживание:)

Ответ 4

Я бы не стал возвращать значение в этом случае. Я бы выбрал исключение, и ваше сообщение содержит значение вашего неверного перечислителя. Для меня неверное значение счетчика представляется ошибкой.

Если вы не хотите этого делать, я согласен с другими, что вы должны возвращать std::string.