4

エラーコードを列挙から文字列にマッピングするより効率的な方法は何でしょうか?(C ++の場合)

たとえば、今私は次のようなことをしています:

std::string ErrorCodeToString(enum errorCode)
{
   switch (errorCode)
   {
      case ERROR_ONE:   return "ERROR_ONE";
      case ERROR_TWO:   return "ERROR_TWO";
      ...
      default:
         break;
   }

   return "UNKNOWN";
}

私がこのようなことをするなら、それは何らかの方法でより効率的でしょうか?:

#define ToStr( name ) # name;

std::string MapError(enum errorCode)
{
   switch (errorCode)
   {
      case ERROR_ONE:   return ToStr(ERROR_ONE);
      case ERROR_TWO:   return ToStr(ERROR_TWO);
      ...
      default:
         break;
   }

   return "UNKNOWN";
}

多分誰かがこれについて何か提案や考えを持っていますか?ありがとう。

4

6 に答える 6

6

マクロを使用する場合は、最後まで行ってみませんか。

std::string MapError(enum errorCode)
{
    #define MAP_ERROR_CODE(code) case code: return #code ;
    switch (errorCode)
    {
       MAP_ERROR_CODE(ERROR_ONE)
       MAP_ERROR_CODE(ERROR_TWO)
       ...
    }
    #undef MAP_ERROR_CODE
    return "UNKNOWN";
}
于 2013-01-11T13:47:30.850 に答える
5

エラー コード (int) と文字列の説明 (任意の文字列) を 1 か所だけで宣言する方法が必要でしたが、上記の例のいずれもそれを許可していません。

そこで、int と string の両方を格納し、int->string 変換の静的マップを維持する単純なクラスを宣言しました。「auto-cast to」int 関数も追加しました。

class Error
{
public:
    Error( int _value, const std::string& _str )
    {
        value = _value;
        message = _str;
#ifdef _DEBUG
        ErrorMap::iterator found = GetErrorMap().find( value );
        if ( found != GetErrorMap().end() )
            assert( found->second == message );
#endif
        GetErrorMap()[value] = message;
    }

    // auto-cast Error to integer error code
    operator int() { return value; }

private:
    int value;
    std::string message;

    typedef std::map<int,std::string> ErrorMap;
    static ErrorMap& GetErrorMap()
    {
        static ErrorMap errMap;
        return errMap;
    }

public:

    static std::string GetErrorString( int value )
    {
        ErrorMap::iterator found = GetErrorMap().find( value );
        if ( found == GetErrorMap().end() )
        {
            assert( false );
            return "";
        }
        else
        {
            return found->second;
        }
    }
};

次に、以下のようにエラー コードを宣言するだけです。

static Error ERROR_SUCCESS(                 0, "The operation succeeded" );
static Error ERROR_SYSTEM_NOT_INITIALIZED(  1, "System is not initialised yet" );
static Error ERROR_INTERNAL(                2, "Internal error" );
static Error ERROR_NOT_IMPLEMENTED(         3, "Function not implemented yet" );

次に、int を返す任意の関数で 1 を返すことができます。

return ERROR_SYSTEM_NOT_INITIALIZED;

また、ライブラリのクライアント プログラムを呼び出すと、「システムはまだ初期化されていません」というメッセージが表示されます。

Error::GetErrorString( 1 );

また:

Error::GetErrorString( ERROR_SYSTEM_NOT_INITIALIZED );

私が見る唯一の制限は、静的なエラー オブジェクトを宣言する .h ファイルが多くの .cpp に含まれている場合に何度も作成されることです (そのため、コンストラクターで _DEBUG テストを実行して、マップの一貫性を確認します)。何千ものエラー コードがない場合、問題にはならないはずです (回避策があるかもしれません...)。

于 2014-02-24T15:09:02.737 に答える
4

提案された代替手段はこれ以上効率的ではありませんが、次の 2 つの方法で改善できます。

  1. errorCode列挙型とこの関数の間には明らかに重複があります。
  2. 列挙値は文字列が与える名前と同じであるため、関数にはある種の重複もあります。

少しプリプロセッサの魔法で両方を修正できます。

// This is your definition of available error codes
#define ERROR_CODES \
  ERROR_CODE(ERROR_ONE) \
  ERROR_CODE(ERROR_TWO) \
  ERROR_CODE(ERROR_THREE)

// Define ERROR_CODE macro appropriately to get a nice enum definition
#define ERROR_CODE(a) ,a
enum ErrorCode {
  None,
  ERROR_CODES
};
#undef ERROR_CODE

// Define ERROR_CODE macro differently here to get the enum -> string mapping
std::string MapError(enum errorCode)
{
   #define ERROR_CODE(a) case a: return #a;

   switch (errorCode)
   {
      case None: return "None";
      ERROR_CODES
   }
}
于 2013-01-11T13:50:02.043 に答える
4
enum errors {
    error_zero,
    error_one,
    error_two
};

namespace {
const char *error_names[] = {
    "Error one",
    "Error two",
    "Error three"
};
}

std::string map_error(errors err) {
    return error_names[err];
}
于 2013-01-11T13:49:05.100 に答える
2

プリプロセッサがコードを渡した後は、2つはまったく同じになります。唯一のことは、2番目のアプローチではエラーが少なくなり、タイプミスが発生しにくくなることです。

あなたが実装したものはすでに良い解決策だと思います。

于 2013-01-11T13:47:15.023 に答える
1

これが古いスレッドであることは知っていますが、Frerich Raabe のアプローチが気に入り、VS でエラーなく動作するようになりました。

#define ERROR_CODES \
    ERROR_CODE(NO_ERROR) \
    ERROR_CODE(ERROR_ONE) \
    ERROR_CODE(ERROR_TWO) \
    ERROR_CODE(ERROR_THREE) \
    ERROR_CODE(ERROR_FOUR)

#define ERROR_CODE(code) code,
typedef enum { ERROR_CODES } ErrorCodes;
#undef ERROR_CODE

const char *MapError(const int errorCode)
{
#define ERROR_CODE(code) case code: return #code;   
    switch (errorCode)
    {
        ERROR_CODES
    default: return "UNKNOWN ERROR";
    };
#undef ERROR_CODE
}
于 2017-01-03T01:50:23.963 に答える