std::type_index能安全用作多态集合键,因其实现了值语义(可拷贝、可移动、重载比较与哈希),而裸type_info不可构造不可拷贝;必须用花括号初始化std::type_index{typeid(T)},避免解析歧义和生命周期问题。

std::type_index 能安全用作多态集合的键,但必须配合 typeid 表达式显式构造,且类型修饰符(const、&、*)差异会导致键不匹配。
std::type_index 为什么能存进 std::map 或 std::unordered_map
因为 std::type_index 是值语义类型:可拷贝、可移动、重载了 operator== 和 operator,还提供 hash_code();而裸的 std::type_info& 不可拷贝、不可构造、无默认比较逻辑,直接塞进容器会编译失败。
常见错误现象:
-
std::map—— 编译报错:use of deleted function 'std::type_info::type_info(const std::type_info&)' -
factory[typeid(MyClass)] = ...—— 错误:不能把临时std::type_info当键(生命周期短 + 不可拷贝) -
std::type_index(typeid(T))写成函数调用形式 —— 某些编译器触发“最令人烦恼的解析”,实际声明了一个函数而非构造对象
正确写法始终是:std::type_index{typeid(T)}(花括号初始化,明确且无歧义)。
多态场景下 typeid 的行为陷阱
对指针或引用做 typeid,结果取决于是否启用 RTTI 和对象是否多态:
-
typeid(ptr)返回指针类型本身(如MyClass*),不是它指向的对象类型 -
typeid(*ptr)才返回实际动态类型(前提是ptr指向多态类,即含虚函数) -
typeid(obj)对值对象总是返回其静态类型;只有对多态对象的引用/解引用才可能获得运行时类型
所以注册工厂时若用 std::type_index{typeid(Concrete)},查询时也得用 std::type_index{typeid(Concrete)},不能混用 const Concrete& 或 Concrete* —— 它们是不同键。
示例:
class Base { virtual ~Base() = default; };
class Derived : public Base {};
Derived d;
Base& b = d;
std::cout <h3>std::unordered_map<:type_index t> 的哈希兼容性</:type_index>
</h3><p>C++11 起标准已特化 <code>std::hash<:type_index></:type_index></code>,主流编译器(GCC/Clang/MSVC)都支持,可直接使用:</p><pre class="brush:php;toolbar:false;">std::unordered_map<:type_index std::function>()>> factory;</:type_index>
但要注意:
-
std::type_index::hash_code()值在单次进程内稳定,但跨进程、跨平台、跨编译器不一致,不能用于持久化或网络传输 - 不要拿
hash_code()当类型唯一 ID 用;只适合内存中快速查找 - RTTI 必须开启(编译器默认通常开,但交叉编译或嵌入式环境可能关),否则
typeid行为未定义
与 std::any.type() 配合做运行时类型分发
当集合中存的是 std::any,可用 .type() 获取其内部 std::type_info&,再转成 std::type_index 查表:
std::any data = 42;
std::unordered_map<:type_index std::string> names;
names[std::type_index{typeid(int)}] = "int";
auto it = names.find(std::type_index{data.type()}); // ✅ 正确
// names.find(data.type()); ❌ 编译失败</:type_index>
关键点:
-
std::any::type()返回const std::type_info&,必须显式包一层std::type_index{...} - 不能用
data.type().name()字符串做键 —— 名字不跨编译器稳定,且无法保证唯一性 - 若
std::any为空(!data.has_value()),data.type()抛出std::bad_any_cast
类型修饰符敏感这点最容易被忽略:注册时用了 std::type_index{typeid(std::string)},但传入的是 const std::string& 的 any,查表就失败 —— 因为 typeid(const std::string&) 和 typeid(std::string) 是两个不同的 std::type_index。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











