The lexical_cast template
We’ll do a little excursion away from serialization to another part of my core library. Basically, lexical_cast
is meant as a template to solve the ever recurring problem of typecasting from numeric types to strings and vice versa.
template< typename O, typename I > inline const O lexical_cast( const I& source ) { std::stringstream s; s << source; O destination; s >> destination; return destination; }
This is the basic implementation. As you see, it makes use of the stringstream
‘s wide range of streaming operands for conversion.
I also added some specializations which string streams could not handle, e.g. converting a bool
to a string
should result in “true” or “false”.
template<> inline const std::string lexical_cast( const bool& source ) { return source ? "true" : "false"; } template<> inline const bool lexical_cast( const std::string& source ) { return source == "true" ? true : false; } // rest omitted for simplicity
This gets more interesting when we look at the enumerations I mentioned before. For example, I have an enum
which defines the nature of an Entity
.
enum EEntityType { ET_ROOT, // identifier for the artificial root entity ET_SCENE, // scenes ET_STATIC, // static entities, e.g. maps, with physics-interaction ET_DYNAMIC, // dynamic entities, e.g. characters, with physics-interaction ET_CAMERA, // cameras ET_LIGHT, // lights ET_SKYBOX // skybox };
Have a look back at the serialization code I presented to you. In line 13, the type of the Entity
is written using writeParameter
and the enum
(which is casted to s32
by the compiler implicitly) as the second parameter (value
) and the lexical_cast
of the enum
to string
as the third parameter (readable
). Since there is no specialization of the template available for EEntityType
yet, this would lead to a conversion from the numeric value to its string representation, e.g. ET_ROOT
becomes “0”.
I would prefer to have a “root” then, and other nice descriptive strings for the other possible values, and that’s what the following lexical_cast
specialization does:
namespace core { template<> inline const std::string lexical_cast( const vte::world::EEntityType& type ) { std::stringstream s; switch( type ) { case vte::world::ET_ROOT: s << "root"; break; case vte::world::ET_SCENE: s << "scene"; break; case vte::world::ET_STATIC: s << "static"; break; case vte::world::ET_DYNAMIC: s << "dynamic"; break; case vte::world::ET_CAMERA: s << "camera"; break; case vte::world::ET_LIGHT: s << "light"; break; case vte::world::ET_SKYBOX: s << "skybox"; break; } return s.str(); } } // namespace core
That way, a nice speaking value is available for the enum
and the XML serializer will gratefully prefer this one over the numeric value. The binary serializer instead doesn’t care and writes the s32
as binary.
The other way round is a bit more complicated. Since s32
could match for any enum
we have, the deserializer will either fill the s32
or the string
parameter which are passed by reference to the readParameter
method. It’s then upon you to deal with the result.
std::string typeString; s32 typeS32; source->readParameter( "type", typeS32, typeString ); vte::world::EEntityType actualType = ET_ROOT; // Did the deserializer return a descriptive type string? if( typeString.length() > 0 ) { // Use the lexical_cast template to convert from string to EEntityType entityType = vte::core::lexical_cast< EEntityType >( typeString ); } else { // Simply cast the returned s32 entityType = (EEntityType) typeS32; }
I’ll leave it to you implement the required template<> inline const vte::world::EEntityType lexical_cast( const std::string& type )
method.
4 Comments