I'm making some kind of serialization using yaml-cpp. For this to work each class has to declare a method using the signature:
template <typename T> void Serialize(T& s);
That T
is a different class when saving and loading. The two class's interface is the same, but I can't make an abstract base class, since most methods are templates. This part is working correctly. I've tried to hook it up with YAML::Node
's operator>>
and YAML::Emitter
's operator<<
.
For operator<<
, I have a working solution, albeit very cruel one. First declare a superclass for all serializable classes:
template <typename T> class Serializable {};
Then I can use the following operator<<
:
template <typename T>
YAML::Emitter& operator<<(YAML::Emitter& out,
Serializable<T>& val)
{
Serializer serializer(out);
reinterpret_cast<T*>(&val)->Serialize(serializer);
return out;
}
This works so far, even though that reinterpret_cast
looks pretty scary, and I'm not sure if it's even legal. I've tried the same for operator>>
, but it didn't work. It looks like this:
template <typename T>
void operator>>(const YAML::Node& node,
Serializable<T>& val)
{
Deserializer deserializer(node);
reinterpret_cast<T*>(&val)->Serialize(deserializer);
}
But gcc (4.6.2) and clang(2.9) both ignore it, and use the operator>>
defined in nodeimp.h (part of yaml-cpp):
template <typename T>
inline void operator >> (const Node& node, T& value) {
if(!ConvertScalar(node, value))
throw InvalidScalar(node.m_mark);
}
So my question is: how should I solve this? Things I absolutely want is to only have a single method for both serialization and deserialization, and to be able to use >> and <<, like if it was a normal type supported by yaml-cpp.
First, about reinterpret_cast
: you actually want static_cast
. In your case, you know that val
is a T
(not just a Serializable<T>
), so you can cast it directly.
Here, I'm assuming you're declaring your classes like
class Foo: public Serializable<Foo> { ... };
reinterpret_cast
will interpret the bytes of val
as a T
, which isn't guaranteed to work, but probably works in your case because you have single inheritance and Serializable<T>
doesn't add any member variables.
Next, on to your real problem: this is a bug in yaml-cpp, and it's now fixed (r52790a15757d if you're keeping up with the mercurial repository, and see http://code.google.com/p/yaml-cpp/issues/detail?id=126 for the issue I opened).
With the above fix, I believe your code should work. If you don't keep up with the repository, then the diff is pretty small - you can patch it in your version of yaml-cpp.