比较来自 typeid() 运算符的两个 type_info

Comparing two type_info from typeid() operator

可以比较两个typeid()结果的结果吗? cppreference 有关于此运算符的注释:

There is no guarantee that the same std::type_info instance will be referred to by all evaluations of the typeid expression on the same type, although std::type_info::hash_code of those type_info objects would be identical, as would be their std::type_index.

const std::type_info& ti1 = typeid(A);
const std::type_info& ti2 = typeid(A);

assert(&ti1 == &ti2); // not guaranteed
assert(ti1.hash_code() == ti2.hash_code()); // guaranteed
assert(std::type_index(ti1) == std::type_index(ti2)); // guaranteed

我的理解是 return 是对类型 type_info 的静态 L 值的引用。它说 &ti1 == &ti2 不能保证相同类型相同。它反而说使用哈希码或 std::type_index class。但是它没有提到是否直接比较类型:

ti1 == ti2; 

保证真实。我以前用过这个,文档是否暗示这是有保证的?

std::type_info is a class-type, which means that the ti1 == ti2 expression will trigger an overloaded operator==. Its behavior is described by [type.info]/p2:

bool operator==(const type_info& rhs) const noexcept;

Effects: Compares the current object with rhs.

Returns: true if the two values describe the same type.

有关实现的一些信息可能很有趣:对于 g++/clang,type_info 以两个指针开头。第二个指向一个固定的字符串,就是name()return编辑的值

** 请注意,此实现不是标准所要求的,并且可能因同一编译器的不同目标而异。

比较是通过首先检查 type_info 是否在同一地址来完成的;如果是这样,他们是平等的;如果不是,接下来在两个 'name' 字符串上调用 strcmp()。并且 strcmp 结果决定了 .before() 方法的顺序(以及 type_index 的顺序)。

通常,对于任何给定的类型,程序中只有一个 type_info。但是,当使用共享库时,有可能在共享库中有一个,而另一个在其他地方。所以,地址的比较不足以判断两个type_info是否代表同一类型,地址也不能用于排序。 如果同一类型存在两个 type_info,它们的 name() 将 return 等效的字符串,但这些字符串将位于不同的地址,因为字符串常量和 type_info 是一起生成的.

.hash_code() 方法令人失望:它调用一个函数来逐个字符地散列 name() 字符串。 g++ 版本调用 strlen 来找到它的 len,然后调用用于 std::hash(std::string) 的相同函数。即使类型不是未知的,也会发生这种情况,例如typeid(std::complex<float>).hash_code()- 编译器原则上可以在编译时计算结果。

在我的 x86_64 clang++-9.0 安装中,我看到了一个奇怪的结果 - hash_code() returns 与 name() 相同,但转换为size_t。这通常会起作用,但在程序中存在两个相同类型的 type_info 的情况下会失败。此外,它不是一个非常丰富的散列,考虑在 64 位地址 space 中出现的值范围。可能是我的安装以某种方式获取了错误的头文件,这就是结果,但它似乎工作正常。也许这是一个实际的缺陷,没有人使用 hash_code() 因为它太慢了......

我为 RISC 处理器尝试了另一个 clang-9,它类似于 hash_code() 的 g++,但不需要调用 strlen。