std::type_index 可安全用作多态集合的键,因其是 std::type_info 的可拷贝、可哈希、可比较包装,解决了裸 type_info 不可构造、不可拷贝、无默认比较符的问题。

std::type_index 可以安全用作多态集合的键,但必须配合 typeid 表达式显式构造,且所有类型必须开启 RTTI、有完整定义、无 cv 限定符干扰。
为什么 std::type_index 能在多态集合里当键用
因为 std::type_index 是 std::type_info 的可拷贝、可哈希、可比较的包装,而裸的 std::type_info& 不可拷贝、不可构造、没有默认 operator,直接塞进 <code>std::map 或 std::unordered_map 会编译失败。多态集合(比如按类型分发消息的 handler 映射)依赖运行时识别真实类型,std::type_index 提供了稳定、安全的值语义支持。
常见错误现象:std::map<decltype int></decltype> 编译不过;factory[typeid(MyClass)] = ... 触发 “use of deleted function”;用 typeid(ptr) 得到的是指针类型,不是所指对象类型。
- 必须用
std::type_index{typeid(obj)}或std::type_index{typeid(*ptr)}获取多态对象的真实类型 - 对基类指针做
typeid(*ptr)才能触发 RTTI 动态识别,前提是该类有虚函数(即多态类型) - 不能用
typeid(T*)当作T的键——它们是完全不同的类型
std::unordered_map<:type_index t> 的哈希陷阱
std::unordered_map<:type_index t></:type_index> 在 C++11 及以后标准中可以直接使用,因为 std::hash<:type_index></:type_index> 已被标准特化。但它的 hash_code() 值是实现定义的:同一程序多次运行可能不同,不能用于持久化或跨进程通信。
常见错误现象:把 std::type_index{typeid(int)}.hash_code() 存数据库,下次启动查不到;用它做网络协议中的类型标识,接收端解析失败。
-
std::type_index::hash_code()只适合单次进程内 O(1) 查找,别当唯一 ID 用 - 若需跨次稳定,得自己基于
type_info::name()做哈希(但名字不跨编译器稳定,慎用) - GCC/Clang/MSVC 都支持标准特化,无需手动写哈希器,除非你禁用了它
cv 限定符和引用修饰导致查不到键
std::type_index 对 const、volatile、引用完全敏感:std::type_index{typeid(int)} 和 std::type_index{typeid(const int)} 不相等,哪怕变量声明为 const int x = 42;。
常见错误现象:注册时用 std::type_index{typeid(MyClass)},查询时传 std::type_index{typeid(const MyClass&)},find() 返回 end();模板函数里写 std::type_index{typeid(T)},T 是引用类型,结果键错位。
- 统一约定:注册和查询都用“值类型”,即
std::type_index{typeid(T{})}或std::type_index{typeid(*obj)} - 避免在模板中直接对
T用typeid(T),应先std::remove_cvref_t<t></t>再取 typeid - 前置声明类不能用
typeid,否则行为未定义;必须确保类型有完整定义
RTTI 关闭时的静默崩溃风险
std::type_index 本身不开启 RTTI,但它依赖 typeid 的行为。如果编译器关闭 RTTI(如 GCC 的 -fno-rtti),typeid 对多态对象求值会触发未定义行为——可能返回 type_info 的静态占位符,也可能直接崩溃。
常见错误现象:嵌入式项目关了 RTTI,typeid(*ptr) 返回的 std::type_index 总是相等;单元测试通过,上线后 segfault;dynamic_cast 失效的同时,typeid 也失效。
- 检查是否开启 RTTI:用
typeid对多态对象测试,对比typeid(Base).name()和typeid(*derived_ptr).name()是否不同 - 非多态类型(无虚函数)的
typeid不依赖 RTTI,但也就失去了“动态识别”能力 - 一旦用了
std::type_index做多态分发,就必须保证所有目标类型是多态的,且编译器开了 RTTI
最易被忽略的一点:类型擦除容器(如自定义 any 替代品)里存 std::type_index 时,注册侧和使用侧对“类型表示形式”的约定必须绝对一致——差一个 const& 就查不到,而且没有任何编译期提示。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











