必须绕开悬垂指针、类型修饰符错配、哈希器缺失三类陷阱:统一用std::type_index{typeid(std::remove_cvref_t{})}构造键,启用rtti并包含和,优先选std::map;若用unordered_map需验证并显式提供std::hash或自定义哈希器。

要在 C++ 中用 std::type_index 作为键在 map 或 unordered_map 里存取不同类型的对象,必须绕开悬垂指针、类型修饰符错配、哈希器缺失这三类静默失效陷阱,否则 find() 永远返回 end(),调试时既不报错也不命中。
确保 RTTI 开启且头文件齐全
RTTI 是 typeid 行为正确的前提,关闭后 typeid(*ptr) 返回静态类型,std::type_index 构造结果不可靠但不报错,只会查不到。
检查编译器选项:GCC/Clang 确认未使用 -fno-rtti;MSVC 确认已启用 /GR(运行时类型信息)。
在源文件顶部必须同时包含两行:#include
插入编译期断言验证:static_assert(__GXX_RTTI || _MSC_VER, "RTTI must be enabled"); 若触发失败,说明环境未就绪,后续所有 type_index 操作都无效。
统一用退修饰的裸类型构造 std::type_index
std::type_index 对 const、&、* 完全敏感——int、const int、int&、int* 全是不同键。注册和查询稍有修饰差异,就彻底无法匹配。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
方法一:注册时固定用值类型表达式
写 factory[std::type_index{typeid(ConcreteA)}] = []{ return std::make_unique
不要写 std::type_index{typeid(const ConcreteA&)},哪怕调用方传的是 const 引用。
方法二:模板函数内安全退修饰
若函数签名为 template
【多态指针必须解引用】 对 Base* ptr,typeid(ptr) 得到的是 Base* 类型键,而实际要存的是派生类行为;必须写 std::type_index{typeid(*ptr)} 才能触发 RTTI 获取动态类型。
选择容器并配置哈希器
第一步:优先选用 std::map<:type_index t>
它依赖 operator
第二步:若坚持用 std::unordered_map,先验证哈希器是否可用
添加 static_assert(std::is_default_constructible_v<:hash>>);
若编译失败,说明当前标准库未特化 std::hash<:type_index>(常见于 GCC 4.8、MSVC 2013 等旧环境)。
第三步:显式传入哈希器或自定义
可行声明:std::unordered_map<:type_index t std::hash>> factory;
或定义 struct type_index_hash { size_t operator()(const std::type_index& ti) const noexcept { return ti.hash_code(); } };
再声明 std::unordered_map<:type_index t type_index_hash> factory;
【禁止自行封装 hash_code() 用于持久化】 它只保证单次运行内一致,跨进程、重启后值可能变化,不能存数据库、不能发网络、不能写日志做类型判定。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










