Originally inspired by Howard Hinnant's type_name code, posted in reponse to:
"How can I see the type deduced for a template type parameter?"
StackOverflow, August 2013.
The implementation is based on C++ typeinfo (RTTI, to become constexpr in C++20).
typeid(T).name()
On GCC, Clang and compilers using the Itanium ABI the result is a mangled name.
On these platforms the name is demangled using the abi::__cxa_demangle()
function.
-
type_name_str<T>()
Returns astd::string
copy of the demangledtypeid
name.
On each call it does all the work, and cleans it all up
(i.e. it frees any demangle allocation once copied from). -
type_name_rt<T>
Astd::string_view
global constant (a view into the
demangle buffer, on CXXABI, which is not ever free'd).
All work is done in static initialization, before main()
- Failure is signaled by an empty return value;
""
(indicates a demangle failure as typeid is assumed failsafe).
C++17 for string_view
, constexpr-if and __has_include
RTTI, the compiler's runtime type information, must be enabled.
From std
:
<cstring>
forstd::strlen
<string>
,<string_view>
as the return values.
<type_traits>
forstd::conditional
.
<typeinfo>
(RTTI) for typeid(T).name(), an implementation-defined name.
<cstdlib>
forstd::free
.
<memory>
forstd::unique_ptr
Platform dependency:
<cxxabi.h>
for demangling (on CXXABI platforms only - GCC, Clang, etc.)
Because the type is supplied as a template parameter, decltype(expr)
is required
to query the type of an expression:
const volatile char abc[1][2][3]{};
std::cout << type_name_rt<decltype(abc)>();
...produces output (different format is possible on different platforms):
char const volatile [1][2][3]
Firstly, note that the type argument has to be provided as a template parameter; type deduction from a regular function argument is not sufficient because deduction cannot distinguish all possible passed types. In other words, it is not possible to wrap decltype()
or implement it otherwise.
In principal, with the type known at compile time, a fully constexpr implementation of type_name<T>
should be possible, for example as a constexpr variable template whose value is some compile-time string type containing the human-readable type name.
In practice, when based on the C++ typeid()
operator, a fully constexpr implementation is not generally possible.
template <typename T>
std::string
type_name()
{
using TR = typename std::remove_reference<T>::type;
std::unique_ptr<char, void(*)(void*)> own (
#ifndef _MSC_VER
abi::__cxa_demangle (typeid(TR).name(), nullptr,
nullptr, nullptr),
#else
nullptr,
#endif
std::free
);
std::string r = own != nullptr ? own.get() : typeid(TR).name();
if (std::is_const<TR>::value)
r += " const";
if (std::is_volatile<TR>::value)
r += " volatile";
if (std::is_lvalue_reference<T>::value)
r += "&";
else if (std::is_rvalue_reference<T>::value)
r += "&&";
return r;
}