将错误代码从枚举映射到字符串的更有效方法是什么? (在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";
}
也许有人对此有任何建议或想法? 感谢。
答案 0 :(得分: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";
}
答案 1 :(得分:5)
我想要一种方法让错误代码(int)和字符串描述(任何字符串)在一个且只有一个地方声明,并且上面的例子都不允许这样做。
所以我声明了一个存储int和string的简单类,并为int->字符串转换维护静态映射。我还添加了一个“自动转换为”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测试以检查映射的一致性)。如果你没有成千上万的错误代码,那应该不是问题(并且可能有解决方法......)
答案 2 :(得分: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];
}
答案 3 :(得分:4)
您建议的替代方案效率不高,但您可以通过两种方式改进:
errorCode
枚举和此功能之间显然存在重复。你可以使用一点预处理器魔法修复两者:
// 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
}
}
答案 4 :(得分:2)
在预处理程序通过代码之后,否则两者将完全相同。唯一的问题是第二种方法不容易出现错别字。
我想说你已经实施的是一个很好的解决方案。
答案 5 :(得分: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
}