serialization - "serialisation without duplication"在 c++0x 中可能吗?

标签 serialization compile-time c++11

C++ 中代码生成的一大用途是支持消息序列化。通常,您希望支持在同一步骤中指定消息内容和布局,并为该消息类型生成代码,以便为您提供能够序列化到通信流或从通信流序列化的对象。在过去,这通常会产生如下所示的代码:

class MyMessage : public SerialisableObject
{
  // message members
  int myNumber_;
  std::string myString_;
  std::vector<MyOtherSerialisableObject> aBunchOfThingsIWantToSerialise_;

public:
  // ctor, dtor, accesors, mutators, then:

  virtual void Serialise(SerialisationStream & stream)
  {
    stream & myNumber_;
    stream & myString_;
    stream & aBunchOfThingsIWantToSerialise_;
  }
};

使用这种设计的问题在于它违反了良好架构的一条重要规则:您不必两次指定设计的意图。意图的重复(如重复的代码和其他常见的开发重复)会导致代码中的某个位置与另一个位置出现分歧,从而导致错误。

上面的重复项是成员列表。潜在的错误包括将成员添加到类中,但忘记将其添加到序列化列表中,将成员序列化两次(可能是由于未使用与成员声明相同的顺序,或者可能是由于类似成员的拼写错误等原因) ,或序列化不是成员的内容(这可能会产生编译器错误,除非名称查找在与匹配查找规则的对象不同的范围内找到某些内容)。这种错误与我们不再尝试将每个堆分配与删除(而不是使用智能指针)或文件打开与关闭(使用 RAII ctor//dtor 机制)相匹配的原因相同 - 我们不希望在多个地方匹配我们的意图,因为有时我们 - 或其他不太熟悉意图的工程师 - 会犯错误。

因此,一般来说,这是代码生成可以处理的事情之一。您可以创建一个文件 MyMessage.cg 来一步指定布局和成员

serialisable MyMessage
{
  int myNumber_;
  std::string myString_;
  std::vector<MyOtherSerialisableObject> aBunchOfThingsIWantToSerialise_;
};

它将通过代码生成实用程序运行并生成代码。

我想知道是否有可能在没有外部代码生成的情况下在 c++0x 中执行此操作。是否有任何新的语言机制可以将类指定为可序列化一次,并且其成员的名称和布局用于在序列化期间布局消息?

需要明确的是,我知道即使在 c++0x 之前的语言中,boost 元组和融合也有一些技巧可以接近这种行为。然而,这些用法基于元组索引而不是按成员名称访问,因此对于更改布局来说都很脆弱,因为代码中访问消息的其他位置也需要重新排序。某种按成员名称访问是必要的,这样就不必在使用消息的代码中重复布局规范。

此外,我知道将其提升到下一个级别并要求指定何时不应序列化某些成员可能会很好。其他提供内置序列化的语言通常会提供某种属性来执行此操作,因此 int myNonSerializedNumber_ [[noserialise]]; 可能看起来很自然。但是,我个人认为拥有可序列化对象(其中所有内容都未序列化)是糟糕的设计,因为消息的生命周期是在往返于通信层的传输中,与其他数据生命周期分开。另外,您可以拥有一个对象,该对象的成员具有纯粹可序列化的功能,因此该语言尚未提供的任何功能都无法实现此类功能。

这可能吗?或者标准委员会是否遗漏了这种内省(introspection)能力?我不需要它看起来像上面的代码生成文件 - 任何简单的一步中布局和成员的编译时规范的方法都可以解决这个常见问题。

最佳答案

这在 C++11 中既可能又实用——事实上,在 C++03 中也是可能的,只是语法有点太笨拙了。我基于相同的想法编写了一个小型库 - 请参阅以下内容:

www.github.com/molw5/framework

示例语法:

class Object : serializable <Object,
    value <NAME(“Field 1”), int>,
    value <NAME(“Field 2”), float>,
    value <NAME(“Field 3”), double>>
{
};

原则上,大多数底​​层代码都可以在 C++03 中重现 - 一些没有可变参数模板的实现细节会......很棘手,但我相信可以恢复核心功能。在 C++03 中无法重现的是上面的 NAME 宏,并且语法相当依赖它。该宏提供了从字符串生成唯一类型名所需的机制,如下所示:

NAME(“Field 1”)

扩展为

 type_string <'F', 'i', 'e', 'l', 'd', ' ', '1'>

通过使用一些常见的宏和constexpr(用于字符提取)。回到 C++03 中,需要手动输入类似于上面的 type_string 的内容。

关于serialization - "serialisation without duplication"在 c++0x 中可能吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7153628/

相关文章:

c++ - 将 std::tuple 的类型转换为 std::pair

java - 在 Java 中扩展 Serializable 类时,我为 serialVersionUID 选择什么重要吗?

C#反序列化带有命名空间的xml

java - 显式的serialVersionUID 被认为是有害的?

c++ - 检测是否设置了某个位(在编译时)

c++ - 编译时间间隔检查器

java - 自动生成值对象

java - kryo 序列化是否适用于不可序列化的类并且类具有不可序列化的属性?

C++11 多线程锁和原子原语

c++ - 如何获取使用标准库创建的线程的 winapi id?