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 astd::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 thetypeid
expression refers to astd::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
- 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.
- 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
, addingsigned
andunsigned
gives you three distinct types in total. - for
short
,int
,long
andlong long
,signed
is implied, and adding that does nothing. Addingunsigned
will give you a new set of distinct types. unsigned
,short
,long
, andlong long
can be followed byint
, but if theint
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
Setting Vector Elements in Range-Based for Loop
Converting from Signed Char to Unsigned Char and Back Again
Move or Named Return Value Optimization (Nrvo)
Why Is Std::Fill(0) Slower Than Std::Fill(1)
Converting Float Values from Big Endian to Little Endian
C++: When (And How) Are C++ Global Static Constructors Called
On Local and Global Static Variables in C++
Easiest Way to Rotate by 90 Degrees an Image Using Opencv
Creating a Counter That Stays Synchronized Across Mpi Processes
Undefined Behaviour Somewhere in Boost::Spirit::Qi::Phrase_Parse
Convert String to Mathematical Evaluation
Reading Line from Text File and Putting the Strings into a Vector
Possible Problems with Nominmax on Visual C++
Does Casting to an Int After Std::Floor Guarantee the Right Result