Question

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.

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top