我正在使用 yaml-cpp 进行某种序列化。为此,每个类都必须使用签名声明一个方法:
template <typename T> void Serialize(T& s);
在保存和加载时,T
是不同的类。这两个类的接口是相同的,但我不能创建一个抽象基类,因为大多数方法都是模板。这部分工作正常。我尝试将其与 YAML::Node
的 operator>>
和 YAML::Emitter
的 连接起来运算符<<
。
对于operator<<
,我有一个可行的解决方案,尽管非常残酷。首先为所有可序列化类声明一个超类:
template <typename T> class Serializable {};
然后我可以使用以下运算符<<:
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) 都忽略它,并使用在 nodeimp.h (yaml-cpp 的一部分)中定义的 operator>>
:
template <typename T>
inline void operator >> (const Node& node, T& value) {
if(!ConvertScalar(node, value))
throw InvalidScalar(node.m_mark);
}
所以我的问题是:我应该如何解决这个问题?我绝对想要的是只有一个方法用于序列化和反序列化,并且能够使用>>和 <<,就像它是 yaml-cpp 支持的普通类型一样。
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.
发布评论
评论(1)
首先,关于
reinterpret_cast
:您实际上需要static_cast
。就您而言,您知道val
是T
(而不仅仅是Serialized
),因此你可以直接投射它。在这里,我假设您声明的类如
reinterpret_cast
会将val
的 字节 解释为T
,这不能保证有效,但可能适用于您的情况,因为您具有单一继承,并且Serialized
不添加任何成员变量。接下来,解决您真正的问题:这是 yaml-cpp 中的一个错误,现已修复(r52790a15757d 如果您正在关注 Mercurial 存储库,请参阅 http://code.google.com/p/yaml-cpp/issues /detail?id=126 对于我打开的问题)。
通过上述修复,我相信您的代码应该可以工作。如果您没有跟上存储库,那么差异非常小 - 您可以在您的 yaml-cpp 版本中修补它。
First, about
reinterpret_cast
: you actually wantstatic_cast
. In your case, you know thatval
is aT
(not just aSerializable<T>
), so you can cast it directly.Here, I'm assuming you're declaring your classes like
reinterpret_cast
will interpret the bytes ofval
as aT
, which isn't guaranteed to work, but probably works in your case because you have single inheritance andSerializable<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.