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中执行此操作。是否有任何新的语言机制可以将类指定为可序列化一次,并且在序列化期间使用它的成员的名称和布局来布局消息?
要清楚,我知道有一些提升元组和融合的技巧,即使在pre-c ++ 0x语言中也可以接近这种行为。但是,这些用法基于索引到元组而不是按成员名称访问,对于更改布局都很脆弱,因为代码中访问消息的其他位置也需要重新排序。某些成员名称访问是必要的,不必在使用消息的代码中的位置复制布局规范。
另外,我知道把它提升到一个新的水平可能会很好,并要求指定什么时候不应序列化。其他提供内置序列化的语言通常会提供某种属性来执行此操作,因此 int myNonSerialisedNumber_ [[noserialise]]; 看起来很自然。但是,我个人认为设置可序列化的对象是不好的设计,因为消息的生命周期是与通信层的传输,与其他数据生命周期分开。此外,您可以拥有一个对象,该对象具有纯粹可序列化的成员,因此该功能不会由该语言提供的任何内容提供。
这可能吗?或者标准委员会是否遗漏了这种内省的能力?我不需要它看起来像上面的代码生成文件 - 任何简单的布局和成员的编译时规范的方法在一个步骤将解决这个常见的问题。
答案 0 :(得分:2)
这在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的东西。
答案 1 :(得分:1)
任何形式的C ++既不支持内省也不支持反思(只要它们不同)。
手动执行序列化(即:没有内省或反射)的一个好处是,您可以提供对象版本控制。您可以支持较旧形式的序列化,只需为旧版本中的数据创建合理的默认值。或者,如果新版本删除了某些数据,您只需序列化并丢弃它即可。
在我看来,你需要的是Boost.Serialization。