std::type_info::name() 返回的是编译器特定的 mangled 名,不可读且不跨平台;GCC/Clang 需用 __cxa_demangle 解析,MSVC 则直接返回可读名;该函数非 constexpr,且对无虚函数类型仅做静态绑定。

std::type_info::name() 返回的不是可读类型名
直接调用 typeid(obj).name() 得到的通常是编译器生成的 mangled 名(比如 GCC 返回 "St6vectorIiSaIiEE"),不是人能一眼看懂的 "std::vector<int>"</int>。这不是 bug,是标准允许的行为 —— std::type_info::name() 只保证返回“实现定义的字符串”,不承诺可读性或稳定性。
常见错误是把它当成品控日志或调试输出直接打印,结果线上日志全是乱码符号,排查时还得手动 demangle。
用 __cxa_demangle 解析 C++ 类型名(GCC/Clang)
Linux/macOS 下最可靠的方式是调用 ABI 函数 __cxa_demangle,它能把 mangled 名转成可读形式。注意:这不是标准 C++ 接口,但 GCC 和 Clang 都提供,且实际项目中广泛使用。
- 需要包含头文件:
<cxxabi.h> - 必须手动管理
free()释放__cxa_demangle分配的内存 - 返回值为
nullptr表示 demangle 失败(比如传入非法 name)
#include <typeinfo>
#include <cxxabi.h>
#include <memory>
#include <string>
<p>std::string type_name(const std::type_info& ti) {
int status = 0;
std::unique_ptr<char, void(<em>)(void</em>)> name{
abi::__cxa_demangle(ti.name(), nullptr, nullptr, &status),
[](void* p) { std::free(p); }
};
return (status == 0) ? name.get() : ti.name();
}
Windows MSVC 下用 typeid(...).name() 就够用了
MSVC 的 std::type_info::name() 默认返回可读字符串(如 "class std::vector<int,class std::allocator<int> >"),不需要额外 demangle。这是 MSVC 的扩展行为,不能跨平台依赖。
立即学习“C++免费学习笔记(深入)”;
如果你只跑 Windows,且不介意名字里带 class/struct 前缀和空格,直接用 typeid(obj).name() 即可。但要注意:MSVC 在 /GR-(禁用 RTTI)下 typeid 会失效,编译报错或运行崩溃。
- 确保编译选项开启 RTTI:
/GR(Visual Studio 默认开) - 不要对
typeid作用于未定义虚函数的类对象(可能触发未定义行为)
动态类型名无法在编译期求值,别想用 constexpr
typeid 是运行时操作,哪怕作用于多态对象,其结果也取决于实际运行时的 vtable 指针。所以 typeid(obj).name() 不可能放进 constexpr 函数,也不能用于模板非类型参数。
如果真需要编译期类型名,只能靠宏或第三方库(如 Boost.TypeIndex),它们本质是把类型名硬编码进字符串字面量,和 typeid 完全无关。这类方案无法反映多态后的真正动态类型 —— 比如 Base* p = new Derived;,宏展开仍是 "Base",而 typeid(*p).name() 才是 "Derived"。
最容易被忽略的一点:typeid 对 non-polymorphic 类型(无虚函数)的对象做静态绑定,只有含虚函数的类才真正体现“动态”类型。没虚函数却想靠 typeid 查子类?那只是查了声明类型而已。


















