Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Same typeid name but not std::is_same

Tags:

c++

c++11

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 ?

like image 219
Ludovic Aubert Avatar asked Apr 12 '16 15:04

Ludovic Aubert


People also ask

What is M in Typeid?

@tomislav-maric the name "m" stands for unsigned long , which happens to be typedef for std::size_t , which happens to be the typedef for std::vector<>::size_type .

What does Typeid mean in C++?

The typeid operator provides a program with the ability to retrieve the actual derived type of the object referred to by a pointer or a reference. This operator, along with the dynamic_cast operator, are provided for runtime type identification (RTTI) support in C++.

What is Type_id?

typeid is an operator in C++. It is used where the dynamic type or runtime type information of an object is needed. It is included in the <typeinfo> library.

What is Typeid used for?

The typeid operator allows the type of an object to be determined at run time. The result of typeid is a const type_info& . The value is a reference to a type_info object that represents either the type-id or the type of the expression, depending on which form of typeid is used.


2 Answers

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>>;
like image 181
Barry Avatar answered Oct 17 '22 18:10

Barry


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.

like image 41
Rakete1111 Avatar answered Oct 17 '22 16:10

Rakete1111