c++oding="utf-8" ?>
typeid(var).name()返回的是编译器实现相关的mangled名(如"st6vectoriisaiiee"),不可读、不可靠、跨平台不一致,需配合abi::__cxa_demangle(gcc/clang)或__undname(msvc)解析。

用 typeid 获取运行时类型名,但结果不可靠
直接调用 typeid(var).name() 能拿到编译器内部的 mangled 名字,比如 St6vectorIiSaIiEE 这种,不是人能读的。它不保证可读性,不同编译器输出差异大,甚至同一编译器在不同优化级别下也可能变化。
常见错误现象:std::cout 打印出乱码或缩写,无法用于调试或日志。
- 仅适用于有 RTTI 的类型(即非
final类、非虚函数被禁用等极端情况) -
typeid对引用和 const 修饰符不敏感:typeid(const int&)和typeid(int)返回相同name() - 返回的字符串生命周期由实现定义,不能长期保存或跨线程使用
用 abi::__cxa_demangle 解析 C++ 类型名
GNU libstdc++ 提供了 abi::__cxa_demangle,能把 typeid(...).name() 的 mangled 字符串转成可读形式,比如 std::vector<int std::allocator> ></int>。
实操要点:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 必须包含头文件:
<cxxabi.h></cxxabi.h> - 需手动管理解码后内存:
abi::__cxa_demangle分配堆内存,必须用free()释放 - 只在 GCC/Clang + libstdc++ 下稳定;MSVC 不支持,要用
__unDName替代 - 示例片段:
int status; char* demangled = abi::__cxa_demangle(typeid(std::vector<int>).name(), nullptr, nullptr, &status); if (status == 0 && demangled) { std::cout </int>
编译期获取类型名:C++20 std::source_location 不行,得靠宏 + __PRETTY_FUNCTION__
std::source_location 只能拿到文件/行号,拿不到类型名。真正实用的是利用编译器扩展的函数签名字符串 —— __PRETTY_FUNCTION__(Clang/GCC)或 __FUNCSIG__(MSVC)。
典型技巧是定义一个模板函数,在其内部提取类型名:
- 用
static constexpr auto type_name = []<typename t>(){ return __PRETTY_FUNCTION__; }().substr(...);</typename>截取关键段(需硬编码起始偏移) - 对
int,__PRETTY_FUNCTION__可能是"auto foo::type_name<int>() [T = int]"</int>,从中抠出"int" - 不支持嵌套模板参数的精确解析(如
std::map<int std::string></int>容易截断) - 宏方案更轻量:
#define TYPE_NAME(x) []{ constexpr auto s = __PRETTY_FUNCTION__; return s.substr(38, sizeof(#x)-1); }(),但依赖宏展开时机和编译器格式稳定性
第三方库或自定义 trait:稳定但要引入额外逻辑
如果项目允许依赖,boost::core::demangle 封装了跨平台解码逻辑,比手撸 abi::__cxa_demangle 更安全;若追求零依赖,可写一个简易 trait 模板特化,为常用类型硬编码名称:
- 例如:
template<typename t> struct type_name { static constexpr auto value = "unknown"; };</typename>,再为int、std::string等显式特化 - 缺点是无法覆盖用户自定义类型,且每次新增类型都要补特化
- 注意:特化时别漏掉 cv-qualifiers 和引用 ——
type_name<const int></const>和type_name<int></int>是不同特化
最麻烦的地方不在“怎么拿”,而在“拿来的名字是否真的能用”:运行时 name 不可读,编译期宏易崩,跨平台解码要分条件编译,而手工特化又难以维护。选哪种,取决于你到底要在日志里打出来、还是做类型分发、还是生成反射元数据 —— 场景一变,方案就得重估。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










