std::any是单值类型擦除容器,仅支持存储一个可复制类型的值,不能自动管理多值或类型调度;它要求类型具拷贝构造、析构不抛异常,取值需显式类型检查,性能低于std::variant。

std::any 不是“任意类型容器”,它是单值包装器,存一个值、取一个值;想存多个不同类型的值,得自己管理 vector<:any> 或类似结构,但别指望它自动帮你做类型调度或迭代安全。
std::any 能存什么、不能存什么
它能存任何可复制(CopyConstructible)类型的值,包括自定义类、int、std::string、甚至 std::vector<double></double> —— 但不能存不完整类型、抽象类对象、或者没有拷贝构造函数的类型(比如只含移动构造的类,除非你显式 move 赋值)。
常见错误现象:std::any a = std::move(my_unique_ptr); 编译失败,因为 std::unique_ptr 不可拷贝;得用 a = std::any{std::move(my_unique_ptr)}; 才行。
- 必须确保被存类型的析构函数不抛异常(否则
std::any析构可能中止) - 空
std::any(默认构造)调用value()会抛std::bad_any_cast,不是空指针或默认值 - 类型擦除带来小开销:每次
value()都要运行时比对 type_info,频繁调用注意性能
怎么安全地取出值:别跳过类型检查
直接 std::any_cast<t>(a)</t> 强制转型,失败就抛异常;更稳妥的是先用 a.type() == typeid(T) 判断,或用指针版 std::any_cast<t>(&a)</t> —— 返回 T*,空指针表示类型不匹配。
立即学习“C++免费学习笔记(深入)”;
使用场景:解析配置项时,键值对的 value 存为 std::any,读取前根据 schema 知道该转成 int 还是 bool,这时指针版更合适,避免异常开销。
- 别写
auto x = std::any_cast<int>(a);</int>就完事,没检查就 crash -
std::any_cast对 const 和引用有重载,std::any_cast<const int>(a)</const>可避免拷贝 - 如果不确定类型,又不想写一堆
if (a.type() == typeid(...)),说明设计可能该用std::variant了
和 std::variant 的关键区别在哪
std::any 是运行时完全擦除类型,std::variant 是编译期限定一组可能类型,空间更紧凑、访问更快、无异常风险(用 std::visit 安全分发)。
性能影响明显:100 万次取值,std::variant 通常比 std::any 快 2–5 倍,且无动态分配(除非装大对象)。
- 如果你知道所有可能类型(比如 JSON 解析只可能是
int/double/std::string/nullptr_t),用std::variant更稳 -
std::any适合插件系统、脚本绑定这类“真不知道将来塞啥”的场景 - 两者都不支持直接序列化;想保存/传输,得自己加类型 tag 和序列化逻辑
最容易被忽略的是:std::any 没有 operator==,也没 hash 支持。想比较两个 any,得先确认类型相同,再手动 cast 后比值 —— 这部分逻辑没人替你写,漏掉就等于没做相等判断。









