Comparing two type_info from typeid() operator
Asked Answered
J

2

8

Is it OK to compare the results from two typeid() results? cppreference has this note about this operator:

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

My understanding is that the the return is a reference to a static L value of type type_info. It's saying &ti1 == &ti2 is not guaranteed to be the same for the same types. It instead says to use the hash code or the std::type_index class. However it doesn't mention if comparing the types directly:

ti1 == ti2; 

is guaranteed to be true. I've used this before, does the documentation implicitly mean this is guaranteed?

Jeffers answered 25/11, 2018 at 13:12 Comment(7)
Youv'e compared them directly before? Their specification doesn't include operator==. Better not do that if you aim for portability.Fronton
@StoryTeller which specification doesn't include operator== ?Turbid
@StoryTeller I may misunderstand you, but there certainly is operator ==.Paschal
@Paschal - Fo real? Am I confusing the need for type_index to work with the insufferable before member?Fronton
@StoryTeller I see no direct need for before when just checking for type identity.Paschal
Hmmm, the examples tend to imply to use hash_code() or type_index, and the wording in the quote seems to me that you shouldn't compare typeid()s or type_infos with each other directly, but I think I'm not understanding the quote if you can in fact compare them safely.Jeffers
@Paschal - Neither do I, but that's what we got in lieu of a proper overloaded order operators. I recalled that member being the reason for the existance of std:: type_index. Seems things weren't quite as bad as I recalled.Fronton
T
6

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.

Turbid answered 25/11, 2018 at 13:20 Comment(1)
Yes. Furthermore, p7 states that hash_code() shall return the same value for instances of type_info that compare. So the guarantee on hash_code() could not be given if not for operator ==.Paschal
P
3

Some information on the implementation could be of interest: for g++/clang, the type_info starts with two pointers. The second one points to a fixed character string, which is the value returned by name().

** Note that this implementation is not required by the standard, and may vary across different targets for the same compiler.

Comparison is done by first checking if the type_info are at the same address; if so, they are equal; if not, next call strcmp() on the two 'name' strings. And the strcmp result determines the ordering for .before() method (and by extension, the ordering for type_index).

Usually, there is only one type_info in the program for any given type. But, when using shared libraries, it's possible to end up with one in a shared library, and another somewhere else. So, comparing the address is not sufficient to test whether two type_info represent the same type, nor can the address be used for ordering. If two type_info exist for the same type, their name() will return equivalent character strings, but those strings will be at different addresses, because the string constant and the type_info are generated together.

The .hash_code() method is disappointing: it calls a function to hash the name() string, character by character. g++ version calls strlen to find its len, and then calls the same function used for std::hash(std::string). And this happens even if the type is not unknown, as in e.g. typeid(std::complex<float>).hash_code()- where the compiler could, in principle, compute the result at compile time.

In my x86_64 clang++-9.0 installation, I'm seeing an odd result - hash_code() returns the same thing as name(), but cast to a size_t. This will often work, but will fail in cases where two type_info for the same type exist in the program. Also, it's not a very rich hash, consider the range of values which occur within a 64-bit address space. It's possible that my installation is somehow getting the wrong header files and this is the result, but it seems to work OK otherwise. Maybe this is an actual defect and nobody uses hash_code() because it's so slow...

I tried another clang-9 for a RISC processor, and it was similar to g++ for hash_code(), but didn't need to call strlen.

Peacetime answered 6/11, 2019 at 21:51 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.