【问题标题】:Serialize C++ object without knowing its fields在不知道其字段的情况下序列化 C++ 对象
【发布时间】:2016-08-02 00:23:21
【问题描述】:

我正在尝试学习如何序列化 C++ 对象。 在这里阅读了几篇文章后,使用boost 序列化函数并使用加载/保存函数进行归档似乎是一个好主意。但是,我想避免使用 boost 库。

从概念上讲,我可以在不知道其字段的情况下保存对象吗?在 C++ 中没有反射,存储对象的唯一方法是知道它的所有类成员。

可以使用stringstream和重载<<操作符将对象转为字符串,可以直接保存对象吗?

谢谢,K。

【问题讨论】:

  • 没有。在没有反思的语言中,除非您知道这些成员是什么,否则您无法对成员做任何事情。
  • 必须有人知道它的字段,可能是它自己。您可以使调用者不需要知道字段,并且有一个用于读取和写入的函数。请注意,序列化有很多棘手的问题,例如版本控制等,这使得一刀切的库成为问题。

标签: c++ serialization


【解决方案1】:

从概念上讲,我可以在不知道其字段的情况下保存对象吗?

不,你不能。

在 C++ 中没有反射,存储对象的唯一方法是知道它的所有类成员。

是的。最好的方法是将这些知识封装在该类本身中:

 class MyClass {
 public:
     std::ostream& put(std::ostream& os) const {
         os << field1 << " " << field2 << std::endl;
         return os;
     }
     friend std::ostream& operator<<(std::ostream& os, const MyClass& myclass) {
         return myClass.put(os);
     }
 private:
     int field1;
     double field2;
 };

【讨论】:

  • 我不喜欢这种设计,因为读写违反干法。添加一个帮助模板,让 io 成为一个具有读取版本读取和写入版本写入功能的功能。
  • @Yakk 你总是可以添加更多级别的间接,这并不妨碍你知道实际的字段在那里(这里是 QED)。
  • 这会很快变得复杂(例如,想象一下如果类有一个字符串字段) - 我认为最好通过为每个命名成员调用一个辅助函数来实现put,辅助函数是重载以支持您将使用的任何成员类型
  • @M.M std::string 字段实际上如何使这种简单的方法复杂化?如果您指的是除了简单的' ' 之外的一些更复杂的分隔符,可以轻松添加/更改这些分隔符。
【解决方案2】:

您可以遵循的一种方法是默认支持 tuple-likes 和 iterables。

拥有一个 read_archive 和 write_archive ,它首先执行花哨的 sfinae 来检测支持 for(:) 循环的类型,以及支持 std::tuple_size 和 ADL get&lt;I&gt; 的类似元组的类型。

这也符合 C++17 中一种形式的结构化绑定支持。

接下来,启用基于to_tie sfinae adl 的实现,检查to_tie()to_tie(.)。如果是这样并且可以读/写,请使用它。

也许其中的某个地方包含一个 archive_io 函数的 adl 查找,因此您可以显式编写自己的 io。

我们的目标是尽可能多地自动存档,以及您无法轻松编写的内容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-31
    • 1970-01-01
    • 2018-11-28
    • 2022-01-22
    • 2022-10-05
    相关资源
    最近更新 更多