std::type_index可安全用作异构容器键,因其可拷贝、可比较、支持哈希,且隐式转换自const std::type_info&;而std::type_info禁止拷贝、无默认构造、不可比较,不能直接作键。

std::type_index 可以安全用作异构容器的键,但必须统一类型修饰、开启 RTTI、避免裸 typeid 临时对象引用——否则查不到、崩溃或行为未定义。
为什么 std::map<:type_index t></:type_index> 能工作,而 std::map<const std::type_info t></const> 不行
因为 std::type_info 禁止拷贝、无默认构造、不支持比较,直接作为键会导致编译失败;std::type_index 是专为容器设计的包装:它可拷贝、可移动、重载了 ==/!=、提供 hash_code(),且能隐式转换自 const std::type_info&。常见错误是写 &typeid(T) 存指针——typeid 返回的是临时对象,取地址后立刻悬垂。
std::unordered_map<:type_index t></:type_index> 编译失败?检查三件事
多数现代标准库(GCC/Clang/MSVC)已特化 std::hash<:type_index></:type_index>,但若报错“no matching function for call to ‘hash’”,说明:
- 编译器标准未设为 C++11 或更高(如 GCC 用
-std=c++98) - RTTI 被显式关闭(如
-fno-rtti),导致typeid行为未定义,连带std::type_index构造失败 - 头文件遗漏:
#include <typeindex></typeindex>和#include <typeinfo></typeinfo>都不可少
查不到注册的类型?大概率是 cv 限定符或引用不匹配
std::type_index{typeid(int)} 和 std::type_index{typeid(const int)} 是两个不同键;std::type_index{typeid(MyClass)} 与 std::type_index{typeid(const MyClass&)} 也不等价。典型场景:
- 注册时用
typeid(Concrete),查询时却传typeid(*ptr)(ptr是Concrete*)——没问题,*ptr是值类型 - 注册用
typeid(Concrete),查询用typeid(std::declval<concrete>())</concrete>——等价,但别混用const版本 - 工厂函数里写
factory.at(std::type_index{typeid(decltype(x))}),若x是const引用,键就带const修饰
和 std::any 搭配做类型擦除容器时的关键约束
用 std::type_index 管理 std::any 的类型映射表很常见,但要注意:
-
std::any::type()返回的是const std::type_info&,必须立刻转成std::type_index再查表,不能缓存该引用 - 注册键必须与
std::any::type()返回的类型完全一致——比如存的是std::any{42},其type()是typeid(int),不是typeid(long)或typeid(unsigned) - 不支持前置声明类:
class X;后直接typeid(X)是非法的,必须有完整定义
最易被忽略的一点:同一类型在不同动态库中生成的 std::type_index 哈希值可能不一致(尽管比较仍正确),跨 DLL/so 边界传递类型键时,优先用比较而非哈希查找。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











