为任意UDT创建可序列化的唯一编译时标识符

时间:2011-01-09 18:50:23

标签: c++ c-preprocessor metaprogramming

我想要一种通用的方法来为任何C ++用户定义的类型创建唯一的编译时标识符 例如:

unique_id<my_type>::value == 0 // true
unique_id<other_type>::value == 1 // true  

我已经设法使用预处理器元编程实现这样的东西,问题是,序列化不一致。例如,如果首先使用unique_id实例化类模板other_type,那么我的程序的先前版本中的任何序列化都将失效。

我已经搜索了这个问题的解决方案,如果唯一值是编译时常量,我找到了几种使用非一致序列化实现它的方法。如果使用 RTTI 或类似方法(如boost::sp_typeinfo),则唯一值显然不是编译时常量,并且存在额外开销。针对此问题的临时解决方案是,以正确的顺序在单独的头中实例化所有unique_id,但这会导致额外的维护和样板代码,这与使用enum unique_id{my_type, other_type};没有什么不同。

这个问题的一个很好的解决方案是使用用户定义的文字,遗憾的是,据我所知,目前没有编译器支持它们。使用udl的语法为'my_type'_id; 'other_type'_id;

我希望有人知道允许在C ++中使用当前标准(C ++ 03 / C ++ 0x)实现可序列化的唯一标识符的技巧,如果它适用于最新的稳定MSVC,我会很高兴GNU-G ++编译器,虽然我希望如果有解决方案,但它不可移植。

我想说清楚,使用mpl::set或类似mpl::vector和过滤等结构,并不能解决这个问题,因为元集/向量的范围是有限的并且实际上导致比预处理器元编程更多的问题。

3 个答案:

答案 0 :(得分:2)

前段时间我向我的一个项目添加了一个构建步骤,这允许我在C ++源文件中编写@script_name(args)并将其自动替换为相关脚本的输出,例如{{1 }或./script_name.pl args

您可能不愿意将语言污染为非标准C ++,但您只需编写./script_name.py args即可获取类名的唯一整数哈希,无论构建顺序如何且没有需要明确的实例化。

这只是众多可能的非标准解决方案中的一种,我认为这个解决方案相当简洁。目前没有很好的方法可以在你的类上强加一个任意的,一致的排序,而不是明确地指定它,所以我建议你简单地放弃并进入显式的实例化路径;集中信息并没有什么不妥,但正如你所说,它与枚举并没有什么不同,这就是我在这种情况下实际使用的。

答案 1 :(得分:1)

数据的持久性是一个非常有趣的问题。

我的第一个问题是:你真的想要序列化吗?如果您愿意调查替代方案,请跳到下一部分。

如果你还在那里,我认为你还没有给出typeid解决方案。

// static detection
template <typename T>
size_t unique_id()
{
  static size_t const id = some_hash(typeid(T)); // or boost::sp_typeinfo
  return id;
}

// dynamic detection
template <typename T>
size_t unique_id(T const& t)
{
  return some_hash(typeid(t)); // no memoization possible
}

注意:我使用本地静态来避免初始化问题的顺序,以防在输入main之前需要此值

它与你的unique_id<some_type>::value非常相似,即使它是在运行时计算的,它只计算一次,然后结果(用于静态检测)被记忆以备将来调用。

另请注意,它完全通用:无需为每种类型显式编写函数。


这可能看起来很愚蠢,但序列化的问题是你在类型及其表示之间有一对一的映射:

  • 您需要对表示进行版本控制,以便能够解码“较旧”版本
  • 处理前向兼容性非常困难
  • 处理循环引用非常困难(某些框架处理它)
  • 然后存在将信息从一个移动到另一个的问题 - &gt;反序列化旧版本变得混乱和令人沮丧

对于持久保存,我通常建议使用专用BOM。将保存的数据视为未来自我的信息。我通常会更加努力,并提出了令人敬畏的Google Proto Buffer库:

  • 向前和向前兼容性烘焙
  • 多种格式输出 - &gt;人类可读(用于调试)或二进制
  • 多种语言可以读/写相同的消息(C ++,Java,Python)

答案 2 :(得分:0)

非常确定你必须实现自己的扩展才能实现这一点,我没有看到也没有听说过编译时这样的构造。 MSVC为预处理器提供__COUNTER__,但我知道没有等效的模板。