2

我正在使用yaml-cpp进行某种序列化。为此,每个类都必须使用签名声明一个方法:

template <typename T> void Serialize(T& s);

T保存和加载时这是一个不同的类。这两个类的接口是一样的,但是我不能做一个抽象基类,因为大多数方法都是模板。这部分工作正常。我试图将它与YAML::Node'soperator>>YAML::Emitter's连接起来operator<<

因为operator<<,我有一个可行的解决方案,尽管非常残酷。首先为所有可序列化的类声明一个超类:

template <typename T> class Serializable {};

然后我可以使用以下内容operator<<

template <typename T>
YAML::Emitter& operator<<(YAML::Emitter& out,
                          Serializable<T>& val)
{
    Serializer serializer(out);
    reinterpret_cast<T*>(&val)->Serialize(serializer);
    return out;
}

到目前为止,这很有效,尽管这reinterpret_cast看起来很可怕,而且我不确定它是否合法。我已经尝试过相同的方法operator>>,但没有奏效。它看起来像这样:

template <typename T>
void operator>>(const YAML::Node& node,
                Serializable<T>& val)
{
    Deserializer deserializer(node);
    reinterpret_cast<T*>(&val)->Serialize(deserializer);
}

但是 gcc (4.6.2) 和 clang(2.9) 都忽略它,并使用operator>>nodeimp.h 中定义的(yaml-cpp 的一部分):

template <typename T>
inline void operator >> (const Node& node, T& value) {
    if(!ConvertScalar(node, value))
        throw InvalidScalar(node.m_mark);
}

所以我的问题是:我应该如何解决这个问题?我绝对想要的是只有一个方法用于序列化和反序列化,并且能够使用 >> 和 <<,就像它是 yaml-cpp 支持的普通类型一样。

4

1 回答 1

0

一、关于reinterpret_cast:你其实想要static_cast。在您的情况下,您知道这val a T(不仅仅是 a Serializable<T>),因此您可以直接转换它。

在这里,我假设你正在声明你的类

class Foo: public Serializable<Foo> { ... };

reinterpret_cast会将 的字节解释val为 a T,这不能保证有效,但可能适用于您的情况,因为您具有单一继承并且Serializable<T>不添加任何成员变量。

接下来,解决您真正的问题:这是 yaml-cpp 中的一个错误,现在已修复(如果您要跟上 mercurial 存储库,请参阅r52790a15757d ,请参阅http://code.google.com/p/yaml- cpp/issues/detail?id=126用于我打开的问题)。

通过上述修复,我相信您的代码应该可以工作。如果您跟不上存储库,那么差异非常小 - 您可以在您的 yaml-cpp 版本中对其进行修补。

于 2011-11-01T22:26:06.077 回答