Ludovic Aubert
Ludovic Aubert

Reputation: 10546

Same typeid name but not std::is_same

Using C++ (gcc 4.8.3) I have 2 types (T1 and T2) which have the strange property that typeid(T1).name() and typeid(T2).name() are the same but std::is_same<T1, T2>::value is false.

How can that be? How can I investigate further to tell what the reason might be ?

Upvotes: 19

Views: 3627

Answers (2)

Barry
Barry

Reputation: 303337

Ignoring polymorphism, typeid() gives you an object representing the static type of the expression. But there are certain elements that are ignored when it comes to expression types. From [expr]:

If an expression initially has the type “reference to T” (8.3.2, 8.5.3), the type is adjusted to T prior to any further analysis. [...] If a prvalue initially has the type “cv T”, where T is a cv-unqualified non-class, non-array type, the type of the expression is adjusted to T prior to any further analysis.

As a result, any types which differ only in top-level cv-qualification or reference will yield the same typeid. For instance, the types int, const int, int& volatile const int&&, etc all give you the same typeid().

Basically, your initial thought process was:

typeid(T) == typeid(U) <==> std::is_same<T, U>

But the correct equivalence is:

typeid(T) == typeid(U) <==> std::is_same<expr_type<T>, expr_type<U>>

where:

template <class T>
using expr_type = std::remove_cv_t<std::remove_reference_t<T>>;

Upvotes: 15

Rakete1111
Rakete1111

Reputation: 48998

typeid ignores all cv-qualifiers:

In all cases, cv-qualifiers are ignored by typeid (that is, typeid(T)==typeid(const T))

(ref)

This means that typeid ignores all references & and const (to name a few).

int i = 0;
const int&& j = 1;

if (typeid(i).hash_code() == typeid(j).hash_code()) //returns true
    std::cout << "typeid(int) == typeid(const int&&)";

Note that to compare 2 typeids, you have to use either typeid(T).hash_code() or std::type_index(typeid(T)), because only for those 2 functions is it guaranteed that 2 same typeids will be the same. Comparing references doesn't have that guarantee for example.

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.

(ref)


As, @Yakk mentioned, you can use std::remove_reference and std::remove_cv to get the behavior you wanted.

std::remove_reference removes all references of T and std::remove_cv removes all const and volatile qualifiers. You should pass T through these functions before passing them to std::is_same, so that std::is_same only compares the underlying type (if any) of T1 and T2.

Upvotes: 6

Related Questions