std::unordered_map 无内置 JSON 序列化能力,C++20 亦未添加;需手动遍历键值对构造 JSON,常见错误是误以为可直接用 std::cout 输出合法 JSON。

std::unordered_map 没有内置 JSON 序列化能力
标准库的 std::unordered_map 不提供 to_json() 或类似接口,C++20 也没加。想导出 JSON,必须手动遍历键值对,拼成 JSON 结构——不是“调个函数就行”的事。
常见错误现象:std::cout 编译失败;用 <code>nlohmann::json 直接构造 json j = my_map; 会触发编译错误(除非你特化了 adl_serializer)。
- 必须显式告诉 JSON 库每个 key 是什么类型、value 怎么映射(比如
int、std::string、嵌套std::map) - 如果 value 是自定义类型,还得额外写序列化逻辑
- key 必须是字符串(JSON object 的 key 只能是 string),而
std::unordered_map的 key 可以是int、std::pair等——这时必须先转成std::string
用 nlohmann/json 最简可行路径
nlohmann/json 是目前最轻量、兼容性最好、语法最直白的 C++ JSON 库。它支持直接从 std::map 构造 object,但对 std::unordered_map 需要一层适配。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 头文件只加
#include <nlohmann></nlohmann>,无需链接 .lib - 把
std::unordered_map<:string t></:string>当作基础场景,T 支持int、double、std::string、std::vector、其他std::unordered_map(递归) - 别用
json::parse()去反向构造,直接用初始化列表或赋值
示例(导出到文件):
#include <nlohmann/json.hpp>
#include <fstream>
#include <unordered_map>
using json = nlohmann::json;
std::unordered_map<std::string, std::string> data = {
{"host", "localhost"},
{"port", "8080"},
{"debug", "true"}
};
json j(data); // ✅ 可行:key 是 string,value 是基本类型
std::ofstream("config.json") << j.dump(2); // 格式化缩进为 2
key 不是 string 时必须手动转换
一旦 std::unordered_map 的 key 是 int、size_t 或自定义结构,json j(map) 会编译失败——JSON 规范不允许非字符串 key。
使用场景:配置项用序号做 key(如 std::unordered_map<int std::string></int> 表示日志级别映射),或用枚举做 key。
- 必须遍历 map,把 key 转成
std::string(例如std::to_string(k)或查表) - 不能依赖自动推导;
json::object()构造器不接受非 string key 的 initializer_list - 性能影响小,但代码多 3–5 行;别试图用宏或模板隐去转换逻辑,可读性反而下降
示例(int key → string key):
std::unordered_map<int, std::string> codes = {{404, "Not Found"}, {500, "Internal Error"}};
json j;
for (const auto& [k, v] : codes) {
j[std::to_string(k)] = v; // ⚠️ key 强制转 string
}
std::ofstream("codes.json") << j.dump(2);
写入文件前务必检查 value 是否可 JSON 化
nlohmann::json 对不可序列化类型(如 std::function、裸指针、std::thread)会在运行时报错或静默丢弃字段,而不是编译报错。
容易踩的坑:
- value 是
std::shared_ptr<t></t>:默认不支持,需自定义adl_serializer,否则整个 entry 被跳过 - value 含二进制数据(如
std::vector<uint8_t></uint8_t>):直接塞进去会变成 base64?不会——它会被当作数字数组,可能不符合预期 - 浮点数精度丢失:默认
dump()保留 17 位有效数字,但若原始值是float,建议先转double再存
安全做法:导出前用 static_assert 或单元测试验证 value 类型是否在已知支持集合内,尤其在多人协作项目中。
复杂点在于,没有银弹——每个业务场景的 value 类型组合不同,适配逻辑得跟着变。别指望一份通用模板覆盖所有 case,老老实实按需处理 key 转换和 value 序列化边界。



















