The template that prints the name of this type

I would like to print the type name for debugging purposes, so I created a function that does the trick (in fact, I borrowed it from another SO answer that I cannot find now), the function looks like this:

template <typename T> std::string TypeName(T) { auto name = typeid(T).name(); int status = 0; std::unique_ptr<char, void(*)(void*)> res { abi::__cxa_demangle(name, NULL, NULL, &status), std::free }; return ((status == 0) ? res.get() : name); } 

Live demo

It works great:

 int i = 0; float f = 0.f; std::cout << TypeName(i) << '\n'; // int std::cout << TypeName(f) << '\n'; // float, so far so good std::cout << TypeName(&i) << '\n'; // int * std::cout << TypeName(&f) << '\n'; // float *, as expected 

But he has no way to handle top-level cv-cualifiers and links:

 const int ci = 1; const float cf = 1.f; std::cout << TypeName(ci) << '\n'; // int! (instead of const int) std::cout << TypeName(cf) << '\n'; // float! (instead of const float) int &ri = i; float &rf = f; std::cout << TypeName(ri) << '\n'; // int! (instead of int &) std::cout << TypeName(rf) << '\n'; // float! (instead of float &) 

Well, I cannot say that this is unexpected, because the TypeName function is a function template, and the T type follows the template type output, but this problem makes it all almost useless.

So my question is: is there anything that can be done to create a template function (which can get any type as input) to get the type name without losing the top levels of cv-cualifiers and links?

Thanks in advance.

+4
source share
1 answer

The only C ++ language construct that can tell the difference between an lvalue, which is an id expression, and an lvalue, which is a reference, decltype . Here is an example of how to use it, including (ab) using a macro to save the same call pattern that you already have:

 template <typename T> std::string TypeName() { auto name = typeid(T()).name(); // function type, not a constructor call! int status = 0; std::unique_ptr<char, void(*)(void*)> res { abi::__cxa_demangle(name, NULL, NULL, &status), std::free }; std::string ret((status == 0) ? res.get() : name); if (ret.substr(ret.size() - 3) == " ()") ret.resize(ret.size() - 3); return ret; } #define TypeName(e) TypeName<decltype(e)>() 

Since abi::__cxa_demangle ignores the top-level cv and reference qualifiers, we construct the type of the function and then separate the end brackets.

This gives int const , int& , int const& as needed.

+1
source

All Articles