c++oding="utf-8" ?>
std::type_index能作map键因其可拷贝、可比较且提供hash_code(),而std::type_info&不可拷贝、无默认比较、无法哈希,故不能直接用作容器键。

std::type_index 可以直接用作异构容器(如 std::map 或 std::unordered_map)的键,但必须确保 RTTI 开启、类型修饰符一致、且避免用临时 typeid 表达式构造悬垂引用。
为什么 std::type_index 能当 map 键,而 std::type_info& 不能
std::type_info 禁止拷贝、不可构造、无默认比较语义,std::map<:type_info t> 直接编译失败;即使退而求其次用指针(std::map),std::type_info::operator== 在部分旧标准下行为未定义,且无法哈希。
std::type_index 是专为解决这个问题设计的包装:它可拷贝、可移动、支持 ==/!=、提供 hash_code(),并能隐式转换自 const std::type_info&。
- 常见错误:写
factory[&typeid(T)] = ...——typeid(T)是临时对象,取地址导致悬垂指针 - 正确做法:始终用
std::type_index{typeid(T)}构造,让type_index内部保存 const 指针并管理生命周期 - 性能影响极小:
std::type_index构造和比较都是 O(1),内部仅存一个const std::type_info*
std::unordered_map<:type_index t> 编译失败?检查 std::hash 特化
虽然 C++11 起标准要求为 std::type_index 特化 std::hash,但部分老版本 libc++ 或自定义 STL 实现可能未完全支持,导致 std::unordered_map<:type_index t> 编译报错 “no matching function for call to ‘hash’”。
- 验证方式:写
static_assert(std::is_default_constructible_v<:hash>>);,不通过即需手动提供哈希器 - 简易修复:用
std::unordered_map<:type_index t std::hash>>显式传入,或在 GCC/Clang/MSVC 主流版本中基本无需干预 - 关键限制:
hash_code()值不跨进程稳定,不能用于持久化、日志记录或网络传输,只适合单次运行内的查找
注册与查询时类型修饰符不一致,查不到键
std::type_index 忠实反映 typeid 的语义:类型修饰符(const、&、*)不同,就是不同键。哪怕你传的是 const int x = 42;,std::type_index{typeid(x)} 和 std::type_index{typeid(int)} 也不等价。
- 典型翻车场景:
- 注册用
std::type_index{typeid(MyClass)},查询却用std::type_index{typeid(const MyClass&)} - 对指针误用
typeid(ptr)(得到指针类型),而非typeid(*ptr)(得到所指对象类型)
- 注册用
- 统一约定建议:工厂/策略注册一律用“值类型”(
typeid(T)),查询时也统一用typeid(declval或()) typeid(T{}),避免依赖变量声明修饰符 - 调试技巧:打印
ti.name()看实际类型名,比如i(int)、PKi(const int*)——名字虽不跨编译器稳定,但同一编译器下可辅助定位差异
和 std::any::type() 混用时的类型匹配陷阱
std::any::type() 返回 const std::type_info&,可直接用于构造 std::type_index,但要注意其生命周期绑定到 std::any 对象本身;若 std::any 被 move 或 reset,该引用失效。
- 安全用法:立即转成
std::type_index,例如handlers.find(std::type_index{data.type()}) - 禁止缓存:不要把
data.type()存成const std::type_info*后长期持有 - 对比
std::any_cast:用data.type() == typeid(T)判断比捕获std::bad_any_cast更轻量,但二者逻辑等价;若已确定类型,优先用std::any_cast提取,避免重复比较开销
最易被忽略的一点是:RTTI 必须开启。GCC/Clang 默认开启,但若加了 -fno-rtti,typeid 行为未定义,所有基于它的 type_index 都会失效——这不是运行时报错,而是未定义行为,可能静默出错或崩溃。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











