可行,但需确保构造方式正确(如std::type_index{typeid(T{})})、类型修饰符统一(如用std::remove_cv_t退修饰)、哈希器就绪(旧编译器需显式提供std::hash或自定义哈希器)。

直接用 std::type_index 作异构容器(如 std::map 或 std::unordered_map)的键是可行的,但多数人卡在“查不到”“编译失败”“跨文件不一致”上——根本原因不是 std::type_index 不行,而是构造方式、类型修饰、哈希器三处没对齐。
std::type_index{typeid(T)} 必须作用于具体表达式,不能写 typeid(T)
模板中直接写 typeid(T) 是非法的:T 是未实例化的类型名,不是表达式。编译器可能静默报错或触发未定义行为。
- 错误写法:
factory[std::type_index{typeid(T)}] = []{...};(T 是模板参数,无求值上下文) - 正确写法:
std::type_index{typeid(T{})}(要求 T 可默认构造)或std::type_index{typeid(std::declval<t>())}</t>(更通用,需#include <utility></utility>) - 最稳妥写法:注册时直接写死类型,如
std::type_index{typeid(ConcreteA)},不依赖模板推导 - 注意:
typeid(T).name()绝对不能当键用——字符串由编译器生成,GCC 输出"i",MSVC 可能是"int",跨编译器/构建完全不可比
注册和查询的类型修饰必须完全一致
std::type_index 对 const、&、* 等修饰符零容忍:哪怕只差一个 const,就是两个不同键。
- 注册用了
std::type_index{typeid(MyClass)},查询却传std::type_index{typeid(const MyClass&)}→find()永远返回end() - 对引用参数
const T& x,要查“值类型”就该用std::type_index{typeid(T)},而不是typeid(x)(后者得到的是const T&) - 对多态指针
Base* ptr,必须用std::type_index{typeid(*ptr)}触发 RTTI 动态识别;typeid(ptr)返回的是Base*类型,毫无意义 - 统一约定:工厂注册与查询一律使用“退修饰后的值类型”,推荐组合
std::type_index{typeid(std::remove_cv_t<:remove_reference_t>>{})}</:remove_reference_t>
std::unordered_map<:type_index t> 编译失败?先验证 std::hash 特化
标准虽从 C++11 起要求特化 std::hash<:type_index></:type_index>,但 GCC 4.8、MSVC 2013 等旧环境仍可能缺失,导致 no matching function for call to ‘hash’。
立即学习“C++免费学习笔记(深入)”;
- 验证是否可用:
static_assert(std::is_default_constructible_v<:hash>>);</:hash>,失败则需干预 - 修复方式一(推荐):改用
std::map<:type_index t></:type_index>,它只依赖operator,而 <code>std::type_index已内置且稳定 - 修复方式二:显式传哈希器,
std::unordered_map<:type_index t std::hash>></:type_index>(主流编译器基本支持) - 切勿手写哈希器调
ti.hash_code()——该值仅单次进程内稳定,不能用于持久化或跨服务比对,且重复封装无必要
RTTI 关闭或头文件遗漏会导致静默失效
关掉 RTTI 后,typeid 行为未定义,std::type_index 构造可能成功但比较结果全错,且编译器不报错。
- 确认开启 RTTI:
-frtti(GCC/Clang 默认开,但项目若显式加了-fno-rtti就得去掉);MSVC 检查是否禁用了/GR- - 头文件缺一不可:
#include <typeindex></typeindex>(提供std::type_index和std::hash特化)和#include <typeinfo></typeinfo>(提供typeid) - 跨动态库时
hash_code()可能不一致,但==比较仍可靠——只要 RTTI 开启、类型修饰一致,同一类型在不同 .so/.dll 中的std::type_index仍能正确相等 - 最容易被忽略的一点:所有
std::type_index实例必须通过值构造(std::type_index{...}),绝不可取临时typeid的地址,否则悬垂指针会在后续比较时引发未定义行为


















