std::type_index比typeid(...).name()更可靠,因其基于标准定义的std::type_info实例地址比较和哈希,跨编译单元对同一类型恒等,且无需手动实现哈希器;而name()由编译器生成、无语义保证、跨平台不一致。

std::type_index 可以安全用作异构容器的键,但必须统一类型修饰、开启 RTTI、避免悬垂引用——否则查不到、崩得悄无声息。
为什么 std::map<:type_index t> 比 typeid(...).name() 更可靠
用 typeid(T).name() 当 map 键是常见误区:名字由编译器生成(GCC 输出 i,MSVC 可能是 int),跨编译器/版本不一致,且无语义保证。而 std::type_index 封装的是运行时类型标识本身,比较和哈希基于标准定义的 std::type_info 实例地址,同一程序中对相同类型总返回相等结果。
- 同一类型在不同编译单元中,
std::type_index{typeid(int)}一定相等 -
std::type_index构造开销极小(仅存一个 conststd::type_info*) - 不用手动写哈希器——C++11 起
std::hash<:type_index></:type_index>已被标准特化,std::unordered_map<:type_index t></:type_index>可直接用
std::type_index 对 const/volatile/&/&& 修饰符完全敏感
注册时用 typeid(MyClass),查询时却传 typeid(const MyClass&),结果必为 find() 返回 end()。这不是 bug,是 typeid 的严格语义:它反映表达式的**完整声明类型**。
- 工厂注册建议统一用“值类型”:如
std::type_index{typeid(ConcreteA)},而非typeid(ConcreteA&) - 若你接收的是 const 引用参数
const T& obj,要查类型请用std::type_index{typeid(T)}(取模板参数),而不是typeid(obj)(得到 const T&) - 指针类型同理:
typeid(int*)和typeid(int)是两个完全不同的键
std::type_index 作 unordered_map 键时的 hash_code() 陷阱
std::type_index::hash_code() 返回值只保证单次进程内哈希一致性,**不能用于持久化、日志记录或网络传输**。它的值在不同进程、甚至同一程序多次启动中都可能变化。
立即学习“C++免费学习笔记(深入)”;
- 不要把
hash_code()当作类型 ID 存数据库或发给其他服务 - 不要基于它做跨进程类型比对逻辑
- 若需稳定标识,应结合
name()+ 编译器/平台白名单校验(但依然不推荐) - 真正可靠的判断永远是
==比较,不是哈希值相等
常见悬垂引用:临时 typeid 结果被存储
最隐蔽的崩溃来源之一:把 typeid(x) 的临时 std::type_info& 地址存进容器,后续访问时该引用已失效。
- 错误写法:
auto& ti = typeid(obj); map[&ti] = value;——ti是临时对象的引用 - 正确做法:始终用
std::type_index{typeid(obj)}构造值对象,它内部持有 const 指针,生命周期独立 - 模板函数中慎用
typeid(T):若T是未实例化的模板参数,行为未定义;应改用typeid(T{})或typeid(typename std::decay_t<t>{})</t>
RTTI 必须开启(GCC/Clang 加 -frtti,MSVC 默认开),否则 typeid 行为未定义,std::type_index 失效。所有主流编译器都支持,但别忘了检查构建配置——这个开关一旦关掉,整个类型映射逻辑就静默退化成不可预测行为。


















