33

In C++11, I am using this

typeid(T).name()

for my own hash computation. I don't need the result to be same between the program runs or compilations. I just need it to be unique for the types. I know, that it can return same name for different types, but it is usually with const, pointers etc. In my case, T is only class XY, struct XX or derived types.

In this case, can I assume, that T will be unique?

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
Martin Perry
  • 9,232
  • 8
  • 46
  • 114

4 Answers4

30

You should use std::type_index for mapping purposes.

The type_index class is a wrapper class around a std::type_info object, that can be used as index in associative and unordered associative containers. The relationship with type_info object is maintained through a pointer, therefore type_index is CopyConstructible and CopyAssignable.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • And `type_index` is safe in this way? E.g. there wont be same `type_index` fo different types? – Martin Perry Nov 01 '16 at 10:48
  • 1
    @MartinPerry scrutinizing the standard, there are no firm affirmation on the uniqueness, but there are several clues in 5.2.8. In addition, Stroustrup himself suggested the use of the address of typeid (i.e. type_info objects) to extend the typeinfo system, also assuming uniqueness. – Christophe Nov 01 '16 at 11:04
  • 4
    @MartinPerry, a conforming implementation may do nothing more than forward to the `std::type_info` pointee. However, using `type_index` takes care of the minutiae involved with making `type_info` a valid key. *Then*, if you find the default `std::hash` specialization works in a sub-optimal fashion, you can create a custom `Hasher` type (or substitute your current one from the get go). – StoryTeller - Unslander Monica Nov 01 '16 at 11:15
19

std::type_info::name is implementation-defined, so you shouldn't rely on it being unique for different types.

Since you're doing this for hash computation, you should use std::type_info::hash_code instead. Although this doesn't guarantee that the values will be unique, the standard says that implementations should try and return different values for different types. So long as your hash map implementation has reasonable collision handling, this should be sufficient for you.

TartanLlama
  • 63,752
  • 13
  • 157
  • 193
  • 6
    `std::type_info::hash_code` is not guaranteed to be unique across types either! – themagicalyang Nov 01 '16 at 10:13
  • @themagicalyang Really? The standard says "an implementation should return different values for two type_info objects which do not compare equal." – TartanLlama Nov 01 '16 at 10:15
  • I didn't check the draft per se, but cppreference says "Returns an unspecified value, which is identical for the type_info objects referring to the same type. No other guarantees are given. For example, the same value may be returned for different types. The value can also change between invocations of the same program" – themagicalyang Nov 01 '16 at 10:19
  • 4
    @TartanLlama see also [this SO question](http://stackoverflow.com/questions/16253207/stdtype-infohash-code-uniqueness-and-the-meaning-of-should) and for use of may/can/should in standards, the [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt): should clearly allows implementation to deviate (even if this is not very probable) – Christophe Nov 01 '16 at 10:19
  • TartanLlama is right apparently, 18.7.2.8 states this. – Hatted Rooster Nov 01 '16 at 10:20
  • @Christophe Ah, that explains it perfectly. I'll edit my answer for correctness. – TartanLlama Nov 01 '16 at 10:21
  • 8
    Well, a hash doesn't have to be perfect. You still have to compare for equality regardless... – Kerrek SB Nov 01 '16 at 10:21
6

As stated on cppreference:

Returns an implementation defined null-terminated character string containing the name of the type. No guarantees are given, in particular, the returned string can be identical for several types and change between invocations of the same program.

So, no, you can't. You can't assume anything actually.

Although, hash_code() gives you:

size_t hash_code() const noexcept;

7 Returns: An unspecified value, except that within a single execution of the program, it shall return the same value for any two type_info objects which compare equal.

8 Remark: an implementation should return different values for two type_info objects which do not compare equal.

Which means that hash_code() can be used to distinguish two different types only if operator== for type_info supports this.

Hatted Rooster
  • 35,759
  • 6
  • 62
  • 122
4

What you might be able to do is take address of a member.

class HashBase {
    virtual intptr_t get() = 0;
};

template <typename T>
class Hash : HashBase {
    static const int _addr = 0;
    intptr_t get() override { return reinterpret_cast<intptr_t>(&_addr); }
};
Oktalist
  • 14,336
  • 3
  • 43
  • 63
themagicalyang
  • 2,493
  • 14
  • 21
  • [C++17 guarantees](https://stackoverflow.com/a/53898701/1136311) the same address of an `inline` variable with external linkage (which includes [static members](https://stackoverflow.com/questions/14872240/unique-address-for-constexpr-variable#comment101477152_53898701), provided the class isn't in an unnamed namespace) across all translation units. If using C++17 (or later), consider making the static member `inline` for a stronger guarantee. – monkey0506 Aug 15 '19 at 13:59