So, I implemented an enumToString
function for several enums that I use a lot (often asked in SO: Is there a simple way to convert C++ enum to string?, Easy way to use variables of enum types as string in C?, ...).
This makes the error messages WAY easier to debug, but I have to maintain the function to add the values that have no string description sometimes.
My code looks like this:
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)";
}
Now, what I want, is that when I don't find the enum in the map, to return "(unknown enum %d)", e
. Which will give me the value of the enum I missed.
This way, even if I didn't add it to the map, I still have its value and I can debug my program.
I can't find a way to do that simply: a stringstream instanciated on the stack will be destroyed right after the return, a static stringstream is not thread-safe, ...
edit: of course, using a std::string
as return type would allow me to format it, but I call these functions very often in my code, I figured passing a const char *
pointer is faster, since I don't have to push the std::string onto the stack each time.
Any solution?
Try defining a thread-local static variable http://gcc.gnu.org/onlinedocs/gcc-3.3.1/gcc/Thread-Local.html
I wouldn't return a value in this case. I would throw an exception and have your message contain the value of your invalid enumerator. To me, an invalid enumerator value would seem to be an error.
If you don't want to do that, then I agree with others that you should be returning a std::string instead.
Personally, I use BOOST :)
Example of use:
Will yield:
Code:
Obviously, it only work with "regular" enums, not with custom made ones. But because it's defined in a single place in the code... no maintenance penalty :)
Return a
std::string
rather than achar*
.This would allow you to use a
std::stringstream
to generate your message. The calling site would then just have to use the.c_str( )
member function onstd::string
to get the C-style pointer (if required).