2

だから、私はenumToStringよく使ういくつかの列挙型の関数を実装しました(SOでよく聞かれます:C ++列挙型を文字列に変換する簡単な方法はありますか?Cで列挙型の変数を文字列として使用する簡単な方法はありますか?、... )。これにより、エラーメッセージのデバッグがはるかに簡単になりますが、文字列の説明がない値を追加する関数を維持する必要がある場合があります。

私のコードは次のようになります。

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)";
}

さて、私が欲しいのは、マップに列挙型が見つからない場合に、を返すこと"(unknown enum %d)", eです。これにより、見逃した列挙型の値がわかります。

このようにして、マップに追加しなくても、その値が残っているので、プログラムをデバッグできます。

それを簡単に行う方法を見つけることができません。スタックにインスタンス化された文字列ストリームは、戻った直後に破棄されます。静的な文字列ストリームはスレッドセーフではありません...

編集:もちろん、return型として使用するとフォーマットできますが、コードでこれらの関数を頻繁に呼び出すので、std :: stringをプッシュする必要がないためstd::string、ポインターを渡す方が速いと思いました。const char *毎回スタック。

解決策はありますか?

4

4 に答える 4

4

std::stringではなくを返しchar*ます。

これにより、を使用しstd::stringstreamてメッセージを生成できます。呼び出し元のサイトは、.c_str( )メンバー関数を使用しstd::stringてCスタイルのポインターを取得する必要があります(必要な場合)。

于 2012-04-16T13:43:56.780 に答える
3

個人的には、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_);

明らかに、それは「通常の」列挙型でのみ機能し、カスタムメイドの列挙型では機能しません。しかし、それはコード内の1つの場所で定義されているため、メンテナンスペナルティはありません:)

于 2012-04-16T16:17:27.043 に答える
0

スレッドローカル静的変数を定義してみてくださいhttp://gcc.gnu.org/onlinedocs/gcc-3.3.1/gcc/Thread-Local.html

于 2012-04-16T13:44:43.597 に答える
0

この場合、値を返しません。例外をスローし、メッセージに無効な列挙子の値を含めます。私には、無効な列挙子の値はエラーのように見えます。

それをしたくない場合は、代わりにstd::stringを返す必要があることに同意します。

于 2012-04-16T13:55:16.957 に答える