将类型序列与iostream混合的最简单方法是什么?

时间:2010-03-24 10:52:34

标签: c++ templates standard-library iostream

我有一个函数void write<typename T>(const T&),它是根据将T对象写入ostream而实现的,以及一个从istream中读取T的匹配函数T read<typename T>()。我基本上使用iostream作为纯文本序列化格式,对于大多数内置类型显然都可以正常工作,尽管我还不确定如何有效地处理std :: strings。

我希望能够写出一系列对象,例如void write<typename T>(const std::vector<T>&)或基于迭代器的等价物(尽管在实践中,它总是与向量一起使用)。但是,虽然编写迭代遍历元素并将其写出来的重载很容易做到,但这并没有添加足够的信息来允许匹配的读操作知道每个元素是如何分隔的,这与我的问题基本相同有一个std :: string。

是否有一种方法可以适用于所有基本类型和std :: string?或者也许我可以逃脱2次重载,一次是数字类型,一种是字符串? (可能使用不同的分隔符或使用分隔符转义机制的字符串。)

编辑:我很欣赏在面对这样的问题时经常明智的倾向,即“你不想那样做”并提出更好的方法,但我真的很喜欢直接相关的建议我问的是什么,而不是你认为我应该问的是什么。 :)

4 个答案:

答案 0 :(得分:1)

一个通用的序列化框架是 hard ,而iostream库的内置功能实际上并不适合它 - 即使处理字符串令人满意也是非常困难的。我建议您坐下来从头开始设计框架,忽略iostream(然后成为实现细节),或者(更现实地)使用现有库,或者至少使用现有格式,例如XML。

答案 1 :(得分:0)

基本上,您必须创建一种文件格式。当您被限制为内置插件,字符串和序列时,您可以使用空格作为分隔符,编写包裹在"中的字符串(转义任何" - 然后\,也 - 在流本身内发生),并选择任何未用于流式传输内置类型的内容作为序列分隔符。存储序列的大小也可能有所帮助。

例如,

5 1.4 "a string containing \" and \\" { 3 "blah" "blubb" "frgl" } { 2 42 21 }

可能是int5),float1.4),字符串("a string containing " and \")的序列化,序列为3字符串("blah""blubb""frgl"),以及2个int s(4221)的序列。

或者你可以像Neil建议的那样in his comment并将字符串视为字符序列:

{ 27 'a' ' ' 's' 't' 'r' 'i' 'n' 'g' ' ' 'c' 'o' 'n' 't' 'a' 'i' 'n' 'i' 'n' 'g' ' ' '"' ' ' 'a' 'n' 'd' ' ' '\' }

答案 2 :(得分:0)

如果你想避免转义字符串,你可以看看ASN.1是如何做的。对于你声明的要求来说这有点过分:字符串,基本类型和这些东西的数组,但原则是流包含明确的长度信息。因此,没有什么需要逃脱。

对于一个非常简单的等价物,您可以输出uint32_t作为“ui4”,然后输出4个字节的数据,int8_t作为“si1”,后跟1个字节的数据,IEEE浮动为“f4”,IEEE双重为“f8”,依此类推。对数组使用一些额外的修饰符:“a134ui4”,后跟536个字节的数据。请注意,任意长度都需要终止,而有界长度(如下一个整数中的字节数)可以是固定大小(ASN.1超出您需要的原因之一是它对所有内容使用任意长度)。然后,字符串可以是a<len>ui1或某些缩写,例如s<len>:。读者确实很简单。

这具有明显的缺点:类型的大小和表示必须独立于平台,并且输出既不是人类可读也不是特别压缩。

你可以使它大部分是人类可读的,但使用ASCII而不是算术类型的二进制表示(小心数组:你可能想要在输出任何数组之前计算整个数组的长度,或者你可以使用分隔符和一个终结符,因为不需要字符转义),并且可选地添加一个大的人类可见分隔符,反序列化器忽略。例如,s16:hello, worlds12:||s12:hello, worlds16:hello, worlds12:s12:hello, world更容易阅读。请注意,当读取看起来像分隔符序列的内容可能实际上不是一个时,你必须避免陷入陷阱,就像在代码中间假设s5:hello||意味着有一个字符串5个字符长:它可能是一部分s15:hello||s5:hello||

除非您对代码大小有非常严格的限制,否则使用现成的通用串行器可能比编写专用的序列化器更容易。使用SAX读取简单的XML并不困难。也就是说,每个人和他的狗都写了“最后,序列化器/解析器/无论什么都能拯救我们手动编码序列化器/解析器/无论再做什么”,取得更大或更小的成功。

答案 3 :(得分:0)

您可以考虑使用boost::spirit,这可以简化从任意输入流中解析基本类型的过程。