std::type_index可作异构容器键,但需避三坑:悬垂指针(禁用&typeid(t))、cv/引用不匹配(须统一退修饰)、跨模块hash不一致;须用花括号初始化、启用rtti、包含必要头文件。

直接用 std::type_index 作异构容器(如 std::map 或 std::unordered_map)的键是可行的,但三类坑不避开——查不到、崩溃、跨平台行为不一致——几乎是必然结果。
为什么 std::type_index 能当键,而 typeid(T) 不能直接用
std::type_info 禁止拷贝、无默认构造、不支持 operator,<code>std::map<const std::type_info t></const> 编译失败;&typeid(T) 更危险:typeid 返回临时对象,取地址即悬垂指针。
std::type_index 是专为容器设计的包装:它可拷贝、可移动、重载了 ==/!=、提供 hash_code(),且能隐式转换自 const std::type_info&。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 必须用
std::type_index{typeid(T)}构造(花括号初始化),避免 most vexing parse - 绝不能写
factory[&typeid(T)] = ...—— 悬垂指针,UB - 注册和查询必须都来自
typeid表达式,不能混用裸指针、引用或 cv 限定类型
std::unordered_map<:type_index t></:type_index> 编译失败?检查这三件事
标准要求 C++11 起特化 std::hash<:type_index></:type_index>,但旧编译器(如 GCC 4.8、某些 MSVC 低版本)或禁用 RTTI 时仍会报 “no matching function for call to ‘hash’”。
- 确认编译标准:至少
-std=c++11,且未加-fno-rtti - 头文件缺一不可:
#include <typeindex></typeindex>和#include <typeinfo></typeinfo> - 若仍失败,显式传哈希器:
std::unordered_map<:type_index t std::hash>></:type_index>,别自己封装ti.hash_code()
查不到注册的类型?90% 是 cv 限定符或引用不匹配
std::type_index 忠实反映 typeid 的语义:int、const int、int&、int* 全是不同键。这不是 bug,是设计使然。
- 注册用
std::type_index{typeid(MyClass)},查询却传std::type_index{typeid(const MyClass&)}→find()返回end() - 模板函数里写
std::type_index{typeid(decltype(x))},若x是const MyClass&,键就带const和& - 统一约定:注册与查询都用“退修饰后的值类型”,即
std::type_index{typeid(std::remove_cv_t<:remove_reference_t>>{})}</:remove_reference_t>,或更简单:统一用std::type_index{typeid(MyClass)}
和 std::any 搭配时最容易被忽略的生命周期陷阱
std::any::type() 返回 const std::type_info&,它只在 std::any 对象生命周期内有效。缓存该引用或取其地址,等于缓存悬垂引用。
- 正确做法:每次查询都立刻转成
std::type_index{any_obj.type()},再查表 - 错误写法:
const std::type_info& ti = any_obj.type(); factory.find(ti);——ti是悬垂引用 - 同一类型在不同动态库中生成的
std::type_index,hash_code()可能不一致,不能用于跨模块共享的映射表
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










