0

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

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

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

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

4

4 回答 4

1

一个通用的序列化框架是很难的,iostream 库的内置特性真的不能胜任——即使令人满意地处理字符串也是相当困难的。我建议您要么坐下来从头开始设计框架,忽略 iostream(然后成为实现细节),要么(更实际地)使用现有的库,或者至少使用现有的格式,例如 XML。

于 2010-03-24T10:57:53.750 回答
0

基本上,您必须创建一个文件格式。当您被限制为内置函数、字符串和它们的序列时,您可以使用空格作为分隔符,写入包裹的字符串"(转义任何"- 然后\,也 - 出现在流本身中),并选择任何不是' t 用于流式传输内置类型作为序列分隔符。存储序列的大小也可能会有所帮助。

例如,

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

可能是一个int( 5)、一个float( 1.4)、一个字符串 ( "a string containing " and \")、一个由 3 个字符串组成的序列 ( "blah""blubb""frgl") 以及一个由 2 个ints (4221) 组成的序列。

或者,您可以按照 Neil在他的评论中建议的那样做,并将字符串视为字符序列:

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

于 2010-03-24T11:22:20.883 回答
0

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

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

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

尽管使用 ASCII 而不是算术类型的二进制表示,但您可以使其大部分可读因为不需要字符转义),并且通过可选地添加一个大的人类可见分隔符,反序列化器会忽略该分隔符。例如,s16:hello, worlds12:||s12:hello, world比阅读要容易得多s16:hello, worlds12:s12:hello, world。请注意,在阅读看起来像分隔符序列的内容实际上可能不是一个分隔符序列时,您必须避免陷入陷阱,例如假设s5:hello||代码中间意味着有一个 5 个字符长的字符串:它可能是s15:hello||s5:hello||.

除非您对代码大小有非常严格的限制,否则使用现成的通用序列化器可能比编写专用序列化器更容易。使用 SAX 读取简单的 XML 并不困难。也就是说,每个人和他的狗都写了“终于,序列化器/解析器/任何东西,这将节省我们再次手动编码序列化器/解析器/任何东西”,或多或少的成功。

于 2010-03-24T12:10:40.330 回答
0

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

于 2010-03-26T01:26:57.317 回答