Typeid' Versus 'Typeof' in C++

typeid' versus 'typeof' in C++

C++ language has no such thing as typeof. You must be looking at some compiler-specific extension. If you are talking about GCC's typeof, then a similar feature is present in C++11 through the keyword decltype. Again, C++ has no such typeof keyword.

typeid is a C++ language operator which returns type identification information at run time. It basically returns a type_info object, which is equality-comparable with other type_info objects.

Note, that the only defined property of the returned type_info object has is its being equality- and non-equality-comparable, i.e. type_info objects describing different types shall compare non-equal, while type_info objects describing the same type have to compare equal. Everything else is implementation-defined. Methods that return various "names" are not guaranteed to return anything human-readable, and even not guaranteed to return anything at all.

Note also, that the above probably implies (although the standard doesn't seem to mention it explicitly) that consecutive applications of typeid to the same type might return different type_info objects (which, of course, still have to compare equal).

typeid pointer and reference comparison difference?

This behaviour is defined by C++17 [expr.typeid]/4:

When typeid is applied to a type-id, the result refers to a std::type_info object representing the type of the type-id. If the type of the type-id is a reference to a possibly cv-qualified type, the result of the typeid expression refers to a std::type_info object representing the cv-unqualified referenced type.

Which is saying that typeid(const T&) and typeid(T&) both give the same result as typeid(T).

Furthermore, point /5 also covers that typeid(T) is the same as typeid(const T). There are not separate flavours of typeinfo for reference-types and const/volatile qualified types. See cppreference summary.

C++ specialization, type_of or just typeid

It's bad because

  1. A, B and C are known at compile-time but you're using a runtime mechanism. If you invoke typeid the compiler will make sure to include metadata into the object files.
  2. If you replace "Do this chunk of code related to A type" with actual code that makes use of CSomeClass's interface you'll see you won't be able to compile the code in case A!=CSomeClass and A having an incompatible interface. The compiler still tries to translate the code even though it is never run. (see example below)

What you normally do is factoring out the code into separate function templates or static member functions of classes that can be specialized.

Bad:

template<typename T>
void foo(T x) {
if (typeid(T)==typeid(int*)) {
*x = 23; // instantiation error: an int can't be dereferenced
} else {
cout << "haha\n";
}
}
int main() {
foo(42); // T=int --> instantiation error
}

Better:

template<typename T>
void foo(T x) {
cout << "haha\n";
}
void foo(int* x) {
*x = 23;
}
int main() {
foo(42); // fine, invokes foo<int>(int)
}

Cheers, s

Comparing two type_info from typeid() operator

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.

Differences between type definions and their meanings in typeid(equalizing)

Some types are the same, some are distinct (=not the same):

  • for char, adding signed and unsigned gives you three distinct types in total.
  • for short, int, long and long long, signed is implied, and adding that does nothing. Adding unsigned will give you a new set of distinct types.
  • unsigned, short, long, and long long can be followed by int, but if the int is there or not does not give distinct types.

In principle, the typeid of all the distinct types should be different. What this means is that template and function overload resolution will view these as different types, whereas e.g. passing a short and short int will both call the same overload.

As far as I'm aware, these rules are the same for C and C++. If I made a mistake, please tell me, I'm writing this off the top of my head.

To check this, you can use static_assert combined with std::is_same for a compile-time check:

#include <type_traits>
using std::is_same;

static_assert(!is_same<char, signed char>(), "");
static_assert(!is_same<char, unsigned char>(), "");
static_assert(!is_same<unsigned char, signed char>(), "");

static_assert( is_same<short, signed short>(), "");
static_assert( is_same<int, signed int>(), "");
static_assert( is_same<long, signed long>(), "");
static_assert( is_same<long long, signed long long>(), "");

static_assert(!is_same<short, unsigned short>(), "");
static_assert(!is_same<int, unsigned int>(), "");
static_assert(!is_same<long, unsigned long>(), "");
static_assert(!is_same<long long, unsigned long long>(), "");

static_assert( is_same<unsigned int, unsigned>(), "");
static_assert( is_same<short int, short>(), "");
static_assert( is_same<long int, long>(), "");
static_assert( is_same<long long int, long long>(), "");

int main(){} // only included to make the program link

Live demo here.

typeid result in different compilers

Gcc is wrong (Bug 68604). S::b is an id-expression referring to a non-static data member, which could be used only in unevaluated context. Gcc seems failing in taking this as unevaluated expression.

As the workaround you could:

std::cout << typeid(decltype(S::b)).name();

Note that in typeid(&S::b).name();, &S::b gives a pointer to member; the result is different with using S::b.



Related Topics



Leave a reply



Submit