How std::type_info::name Handles Name Mangling in C++

In C++, the std::type_info::name() member function provides an identifier for a given data type at runtime through Run-Time Type Information (RTTI). However, the C++ standard does not mandate a human-readable format, leaving the output implementation-defined. Consequently, most compilers return the compiler-specific "mangled" name of the type—a symbol encoded with structural metadata such as namespaces, template parameters, and qualifiers—rather than its literal source-code representation. Understanding how std::type_info::name() produces these decorated names and how to demangle them is essential for effective runtime type inspection and debugging.

The Standard Specification of std::type_info::name

According to the ISO C++ standard, std::type_info::name() returns a pointer to a null-terminated string (const char*) that represents the type. The standard establishes only minimal guarantees:

  • The returned pointer remains valid throughout the program execution.
  • The string identifies the type, but identical types are only guaranteed to produce equivalent representations within the same execution context.
  • The formatting, readability, and content of the string are entirely defined by the implementation (the compiler).

Because the standard avoids dictating a human-readable format, compiler vendors prioritize internal efficiency and linkage semantics, frequently exposing the internal ABI (Application Binary Interface) representation directly.

The Role of Name Mangling

Name mangling is a technique employed by C++ compilers to preserve type information through the compilation and linking phases. Because C++ allows function overloading, namespaces, classes, and templates, the linker requires distinct, unique symbol names that plain C-style identifiers cannot supply.

When std::type_info::name() is invoked, compilers often return this underlying ABI-level decorated string. The string encodes:

  • Namespaces and class scoping.
  • Template arguments and specialization details.
  • Type qualifiers such as const, volatile, and references.

Compiler Implementations: GCC and Clang vs. MSVC

Different toolchains handle std::type_info::name() distinctly based on their platform ABIs:

GCC and Clang (Itanium C++ ABI)

Compilers adhering to the Itanium C++ ABI (common on Linux, macOS, and many embedded platforms) return raw mangled symbols from name().

  • Primitive types yield single-character abbreviations: int produces "i", double produces "d", and char produces "c".
  • Complex types produce structured symbols: std::string appears as a symbol such as "NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE".

Microsoft Visual C++ (MSVC)

MSVC behaves differently. Its implementation of std::type_info::name() automatically demangles the internal name and returns a human-readable string, such as "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >". For access to the raw decorated string under MSVC, the non-standard member function std::type_info::raw_name() must be called instead.

Demangling Names at Runtime

Because Itanium ABI implementations expose raw mangled symbols, translating the string into a human-readable format requires compiler-specific runtime utilities.

In GCC and Clang, the C++ runtime provides the abi::__cxa_demangle function declared in the <cxxabi.h> header:

#include <iostream>
#include <typeinfo>
#include <cxxabi.h>
#include <memory>
#include <string>

std::string demangle(const char* mangled_name) {
    int status = 0;
    std::unique_ptr<char, void(*)(void*)> res{
        abi::__cxa_demangle(mangled_name, nullptr, nullptr, &status),
        std::free
    };
    return (status == 0) ? res.get() : mangled_name;
}

For MSVC, if working directly with decorated names from raw_name(), the Windows API provides the UnDecorateSymbolName function through the DbgHelp.h library.

Portability Considerations

Because std::type_info::name() relies entirely on implementation-defined behavior, developers should adhere to the following best practices:

  1. Avoid Serialization: Do not persist the output of name() across disk, network, or process boundaries, as strings can change between compiler versions or build flags.
  2. Avoid Control Flow Logic: Do not write conditional code based on string comparisons of name(). Use std::type_index or the == and != operators on std::type_info instances for robust, portable type comparisons.
  3. Use for Diagnostic Logging Only: Treat the return value strictly as an aid for debugging, logging, and diagnostics where absolute cross-platform consistency is not required.