C++ keyword typeid
has a magic: it know when to use compile-time type info and when to use runtime type info:
#include <iostream>
#include <typeinfo>
using namespace std;
struct Interface { virtual void f() = 0; };
struct S1 : Interface { void f() { cout << "S1\n"; }};
struct S3 : S1 { void f() { cout << "S3\n"; }};
int main() {
S1 s1;
cout << typeid(s1).name() << endl;
S1* ps = new S3;
cout << typeid(ps).name() << endl;
cout << typeid(*ps).name() << endl;
delete ps;
return 0;
}
The program prints:
struct S1
struct S1 * __ptr64
struct S3
My question: does gcc/clang compiler has any compiler macro, or type_traits : that exposes typeid
magic and tells us whether typeid(*ps)
is compile-time determined or runtime-determined?
Check this out:
template<typename T>
constexpr auto my_typeId(const T& value) {
auto compileTimeChecked{ true };
const auto& typeId = typeid(compileTimeChecked = false, value);
return std::pair<
decltype(compileTimeChecked),
decltype(typeId)
>{ compileTimeChecked, typeId };
}
The first argument of the pair has true
if typeid
is resolved at compile time. false
otherwise. The second member is the reference to the resolved type information const std::type_info &
The trick here is that typeid
semantic changes depending on the argument it takes. If argument is an instance of a polymorphic class, then typeid
actually evaluates the expression in runtime, and the side effect of compileTimeChecked = false
comes into play. Otherwise typeid
does not evaluate the expression (thus, compileTimeChecked = false
never happens), but just takes the static type of value
resolved at compile-time.
Edit: as pointed out by user17732522 in the comments,
be advised that when value
is a polymorphic prvalue, my_typeId
function actually evaluates it in runtime, unlike the typeid
which, if passed directly, resolves the type statically. This difference is apparently impossible to get rid of when using functions, just because of how function call work in C++.