序列化模式类似于boost::序列化

serialization pattern similar to boost::serialization

本文关键字:序列化 boost 类似于 模式      更新时间:2023-10-16

我有一堆类,可以通过以下接口从JSON对象解析并序列化为JSON对象:

class Message
{
public:
virtual ~Message() {}
virtual void parse(const Json::Value &v) = 0;
virtual void serialize(Json::Value &v) const = 0;
};

我想实现一个类似于boost::serialization的模式,这样我就必须在对象中只定义一个方法(void setup(...),是的,我知道,这是一个糟糕的命名选择(,它可以双向工作(解析和序列化(。这也有提供抽象层的好处,这样将来我就可以切换到不同的序列化(YAML?BSON?CBOR?(,而无需重写每个对象中的所有序列化代码。

所以我做了以下事情:

class Message2;
struct MessageFields
{
Json::Value *outValue;
const Json::Value *inValue;
virtual void map(const std::string &name, bool *field) {
*field = (*inValue)[name].asBool();
}
virtual void map(const std::string &name, const bool *field) {
(*outValue)[name] = *field;
}
virtual void map(const std::string &name, int *field) {
*field = (*inValue)[name].asInt();
}
virtual void map(const std::string &name, const int *field) {
(*outValue)[name] = *field;
}
virtual void map(const std::string &name, std::string *field) {
*field = (*inValue)[name].asString();
}
virtual void map(const std::string &name, const std::string *field) {
(*outValue)[name] = *field;
}
...
};

以及:

// the new base class:
class Message2 : public Message
{
virtual ~Message2() {}
// the new method to implement:
virtual void setup(MessageFields &fields) const = 0;
virtual void parse(const Json::Value &v)
{
MessageFields fields;
fields.inValue = &v;
setup(fields);
}
virtual void serialize(Json::Value &v) const
{
MessageFields fields;
fields.outValue = &v;
setup(fields);
}
};

在我的对象中,而不是实现两种方法:

// class SomeObject : public Message { public: std::string node_name; };
void SomeObject::parse(const Json::Value &v)
{
node_name = v["node_name"].asString();
}
void SomeObject::serialize(Json::Value &v) const
{
v["node_name"] = node_name;
}

只需要实现:

// class SomeObject : public Message2 { public: std::string node_name; };
void SomeObject::setup(serialization::MessageFields &fields) const
{
fields.map("node_name", &node_name);
}

除了在写完这篇文章后,我意识到setup(...)就是const,所以对MessageFields::map(...)的调用总是解析为const版本。

为了解决这个问题,我必须编写两个相同版本的setup(...)方法,一个是const,另一个不是,但这种方法违背了只编写一个方法来执行这两个操作的最初目的。

你知道怎么解决这个问题吗?

如果不可能保持常量的正确性(正如我所怀疑的(,那么将Message::serializeMessage2::setup更改为非常量的解决方案也会起作用。

根据@BartoszKP的建议,我从void Message2::setup(MessageFields &fields)中删除了const

这也需要改变:

void Message2::serialize(Json::Value &v) const
{
serialization::MessageFields fields;
fields.outValue = &v;
const_cast<Message*>(this)->setup(fields);
}

并且只有非常数MessageFields::map(...)方法,该方法将通过检查在MessageFields::inValueMessageFields::outValue之间设置了哪个值来判断两个操作中的哪一个正在进行(即解析或序列化(。


注意:我不能接受这个答案,因为根据https://isocpp.org/wiki/faq/const-correctness