std::type_index是typeid返回值的可拷贝、可哈希包装器,仅支持以typeid(…)显式构造,不提供默认或裸指针构造,其比较与哈希依赖底层type_info实现。

std::type_index 是 typeid 返回值的包装器
typeid 表达式在运行时返回一个 const std::type_info&,它不可拷贝、不可赋值,也不能直接用作容器键或 unordered 容器的哈希目标。std::type_index 就是为解决这个问题而设计的:它内部持有一个 const std::type_info*,并提供了拷贝、比较、哈希等操作符重载。
必须用 typeid(…) 构造 std::type_index,不能直接 new 或默认构造
std::type_index 没有默认构造函数,也不接受裸指针构造。它只接受 typeid 表达式作为参数:
std::type_index ti1 = typeid(int); std::type_index ti2 = typeid(std::string); // ✅ 正确:传入 typeid 结果 std::type_index ti3(typeid(double)); // 也合法,显式构造 // ❌ 错误:std::type_index ti; // 编译失败 // ❌ 错误:std::type_index ti(*some_type_info_ptr); // 没有该构造函数
比较和哈希行为完全依赖 underlying type_info 的实现
std::type_index 的 ==、 和 std::hash<:type_index> 都转发给其内部持有的 type_info 对象。这意味着:
- 两个
std::type_index相等 ⇔ 它们封装的type_info指向同一类型(包括 cv 限定和引用修饰) -
std::type_index可安全用作std::map或std::unordered_map的 key - 但注意:
typeid(int)和typeid(const int)是不同type_info,因此std::type_index也不同 - 某些编译器(如 GCC)对模板实例化类型可能生成多个
type_info地址(尤其跨 DSO 边界),此时==可能失效 —— 这不是std::type_index的问题,而是typeid本身的 ABI 限制
实际用途:替代裸 type_info 做类型注册与分发
最常见的使用场景是构建运行时类型映射表,比如插件系统或序列化框架中按类型查找处理函数:
立即学习“C++免费学习笔记(深入)”;
std::unordered_map> handlers; handlers[typeid(int)] = [](void* p) { std::cout << *static_cast(p) << 'n'; }; handlers[typeid(std::string)] = [](void* p) { std::cout << *static_cast(p) << 'n'; }; // 后续可安全调用: void dispatch(const std::type_info& ti, void* ptr) { auto it = handlers.find(std::type_index(ti)); if (it != handlers.end()) it->second(ptr); }
这里必须用 std::type_index 才能放进 std::unordered_map;若直接存 const std::type_info&,不仅无法哈希,生命周期也难以管理。
真正容易被忽略的是:哪怕你只在单个 .cpp 文件里用 typeid,只要涉及跨编译单元取地址(比如把 &typeid(T) 存进全局 map),就可能撞上 ABI 不一致问题 —— 此时 std::type_index 不会帮你绕过,它只是让 type_info 更好用,而不是更可靠。