Is there a way to serialize automatically enums as int?
Is there a way to serialize enums automatically as int? Every time I define a new enum and write
std::stringstream stream;
stream << myenum1;
stream >> myenum2;
the compiler complains that the <and → operators are not defined. Do you know a way to tell the compiler to treat enums as simple int's?
What complicates the problem is that the serialization is inside the template. Something like that:
template <typename T>
void serialize(const T& value)
{
std::stringstream stream;
stream << value;
}
So I can't add any roles :( Maybe I can specialize it somehow?
Thanks.
a source to share
You can find out if a type is an enum with boost TypeTraits ( is_enum ).
Then you can combine this with enable_if
/ disable_if
:
template <class T>
typename boost::disable_if<boost::is_enum<T> >::type serialize(const T&);
template <class T>
typename boost::enable_if<boost::is_enum<T> >::type serialize(const T&); //use casts here
However, it will fail to check if the given value is actually valid for the given enumeration (unless you have written a specific overload for the given enumeration type).
a source to share
For output, the operator <<
will support any type of enumeration up to the nearest match int
or long
. (§5.8 / 1, 4.5 / 2). You shouldn't have any problems and I couldn't produce any GCC or Comeau. Correct me if I am wrong.
For input, you can write a template function and disable the implicit instance by hiding it inside only an explicitly defined class.
template< class E >
struct enum_traits {
friend std::istream &operator>> ( std::istream &is, E &e ) {
long i; // or intmax_t, whatever
std::istream &r = is >> i;
e = E( i );
return r;
}
};
enum my_enum { a, b, c };
template class enum_traits< my_enum >; // explicit instantiation
// "matching declaration" per 7.3.1.2/3:
std::istream &operator>> ( std::istream &, my_enum & );
This goes through the GCC and Comeau. I can't find a way to break namespaces and ADL to make it more convenient. (Only an alternative solution involves using a declaration for each enumerator.)
But the two template declarations can be wrapped in a macro, or either way they are better than writing the entire function again!
a source to share
Do you know a way to tell the compiler to treat enums as simple int's?
This is not possible (at least for ->), since it would not be type-safe (int assignment to enumeration is not type-safe).
One thing you can do is provide you with operator overloads → and <for each enum, which will do the casting for you. This is what you will do for each enum once, which sounds much better than using it in every place where you use → / <(which is especially handy here, since you cannot edit the places where these operators are used) ...
a source to share
This will improve with C ++ 0x as you will be able to specify the base type (for example unsigned short
).
Now you need to use a convention, for example, assuming all your enum values can be stored in int
, you can serialize and deserialize it as an int and then convert back.
Another problem is, of course, your serialization routine:
std::stringstream stream;
stream << 1 << 2;
int a;
stream >> a;
assert(a == 12);
Serialization usually involves getting a binary representation of a known size (or serializing the size along it). If you don't want to do this yourself, there are libraries:
- Boost.Serialization
- Google.ProtocolBuffers
And both have text and binary representation (and plain text is easier to debug).
a source to share