C++11 - typeid uniqueness
Asked Answered
K

4

34

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?

Knifeedged answered 1/11, 2016 at 10:10 Comment(2)
Related: #28862260Delocalize
The only one who can guarantee that T is unique is you. Are you sure you've asked the right question?Forestaysail
T
31

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.

Titbit answered 1/11, 2016 at 10:16 Comment(3)
And type_index is safe in this way? E.g. there wont be same type_index fo different types?Knifeedged
@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.Aholla
@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).Titbit
H
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.

Hubble answered 1/11, 2016 at 10:12 Comment(7)
std::type_info::hash_code is not guaranteed to be unique across types either!Consign
@Consign Really? The standard says "an implementation should return different values for two type_info objects which do not compare equal."Hubble
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"Consign
@Hubble see also this SO question and for use of may/can/should in standards, the RFC 2119: should clearly allows implementation to deviate (even if this is not very probable)Aholla
TartanLlama is right apparently, 18.7.2.8 states this.Floatable
@Aholla Ah, that explains it perfectly. I'll edit my answer for correctness.Hubble
Well, a hash doesn't have to be perfect. You still have to compare for equality regardless...Climb
F
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.

Floatable answered 1/11, 2016 at 10:13 Comment(0)
C
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); }
};
Consign answered 1/11, 2016 at 10:17 Comment(1)
C++17 guarantees the same address of an inline variable with external linkage (which includes static members, 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.Tumpline

© 2022 - 2024 — McMap. All rights reserved.