最直接的方式是 typeid(var).name(),但返回编译器内部修饰名;需配合 __cxa_demangle 解码才可读,且平台相关;真正类型判断应使用 std::is_same_v 或概念。

用 typeid 配合 name() 最直接,但返回的是编译器内部名称
在调试或日志中想打印变量类型时,typeid(var).name() 是最常用的组合。它不依赖模板推导,也不需要 C++11 以上,但要注意:name() 返回的是未修饰(mangled)的实现相关字符串,比如 GCC 可能返回 i 表示 int,Clang 可能是 i 或 int,MSVC 更接近可读名但仍有缩写。
- 必须包含头文件
<typeinfo></typeinfo> - 对带 cv 限定符(如
const int&)或引用类型,typeid会忽略顶层 const 和引用,只反映“所指对象”的类型 - 若变量是多态类对象且含虚函数,
typeid在运行时返回实际动态类型;否则是静态类型
std::string_view + __cxa_demangle(Linux/macOS)才能拿到可读名
要真正看到 std::vector<:string></:string> 这样的名字,得解码 mangled 名。GCC/Clang 下靠 abi::__cxa_demangle,但它是非标准、平台相关的 C 函数,需手动链接 libstdc++ 或 libc++。
- 需要
<cstdlib></cstdlib>、<memory></memory>和<cxxabi.h></cxxabi.h>(后者非标准,但广泛存在) - 解码后内存由
malloc分配,必须用free释放,否则泄漏 - Windows 上无原生等价接口,MSVC 的
typeid(T).name()已接近可读,但嵌套模板仍可能缩写(如class std::basic_string...)
#include <typeinfo>
#include <memory>
#include <cstdlib>
#include <cxxabi.h>
<p>std::string demangled_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();
}</p>模板 + decltype + std::string_view(C++17 起)更安全但编译期固定
如果只是想在编译期把类型名“字面量化”,比如用于 static_assert 错误信息或宏展开,可以借助模板和 __PRETTY_FUNCTION__(GCC/Clang)或 __FUNCSIG__(MSVC)提取。这种方式不调用运行时 API,也规避了 abi::__cxa_demangle 的平台限制。
- 依赖编译器扩展,不可移植,但稳定可靠
- 提取逻辑需用模板特化或 constexpr 字符串处理(C++20
std::string_view::substr可简化) - 对 auto 变量或复杂模板实例(如
std::map<int std::optional>></int>)效果好,但无法处理运行时类型(如多态对象的实际子类)
别忘了 std::is_same_v 和概念(C++20)才是真·类型判断
如果目标不是“打印名字”,而是“做类型分支”或“约束函数参数”,硬解析类型名是反模式。C++ 提供了更健壮的方式:
立即学习“C++免费学习笔记(深入)”;
-
std::is_same_v<t int></t>判断是否为某具体类型 - 函数重载 + SFINAE 或
requires概念,让编译器按类型选最佳匹配 - 运行时多态场景下,优先用虚函数或
std::variant/std::any,而非靠类型名字符串做 if-else
类型名字符串本质是调试辅助,不是类型系统的一部分——一旦开始用 if (name == "St6vectorI...") 做逻辑分支,就踩进了维护地狱。


















