nlohmann/json
GitHub: nlohmann/json
专为现代 C++ 设计的直观 JSON 库,以单一头文件形式提供极简的序列化与数据操作能力。
Stars: 49012 | Forks: 7322
[](https://github.com/nlohmann/json/releases)
[](https://ci.appveyor.com/project/nlohmann/json)
[](https://github.com/nlohmann/json/actions?query=workflow%3AUbuntu)
[](https://github.com/nlohmann/json/actions?query=workflow%3AmacOS)
[](https://github.com/nlohmann/json/actions?query=workflow%3AWindows)
[](https://coveralls.io/github/nlohmann/json?branch=develop)
[](https://scan.coverity.com/projects/nlohmann-json)
[](https://app.codacy.com/gh/nlohmann/json/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
[](https://cirrus-ci.com/github/nlohmann/json)
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:json)
[](https://wandbox.org/permlink/1mp10JbaANo6FUc7)
[](https://json.nlohmann.me)
[](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT)
[](https://github.com/nlohmann/json/releases)
[](https://repology.org/project/nlohmann-json/versions)
[](https://github.com/nlohmann/json/releases)
[](https://github.com/nlohmann/json/issues)
[](https://isitmaintained.com/project/nlohmann/json "Average time to resolve an issue")
[](https://bestpractices.coreinfrastructure.org/projects/289)
[](https://scorecard.dev/viewer/?uri=github.com/nlohmann/json)
[](https://cloudback.it)
[](https://github.com/sponsors/nlohmann)
[](https://api.reuse.software/info/github.com/nlohmann/json)
[](https://discord.gg/6mrGXKvX7y)
- [设计目标](#design-goals)
- [赞助者](#sponsors)
- [支持](#support) ([文档](https://json.nlohmann.me), [FAQ](https://json.nlohmann.me/home/faq/), [讨论](https://github.com/nlohmann/json/discussions), [API](https://json.nlohmann.me/api/basic_json/), [Bug 问题](https://github.com/nlohmann/json/issues))
- [快速参考](#quick-reference)
- [示例](#examples)
- [从文件读取 JSON](#read-json-from-a-file)
- [从 JSON 字面量创建 `json` 对象](#creating-json-objects-from-json-literals)
- [JSON 作为一等数据类型](#json-as-a-first-class-data-type)
- [序列化 / 反序列化](#serialization--deserialization)
- [类似 STL 的访问方式](#stl-like-access)
- [从 STL 容器转换](#conversion-from-stl-containers)
- [JSON Pointer 和 JSON Patch](#json-pointer-and-json-patch)
- [JSON Merge Patch](#json-merge-patch)
- [隐式转换](#implicit-conversions)
- [与任意类型相互转换](#arbitrary-types-conversions)
- [特化枚举转换](#specializing-enum-conversion)
- [二进制格式 (BSON, CBOR, MessagePack, UBJSON, 以及 BJData)](#binary-formats-bson-cbor-messagepack-ubjson-and-bjdata)
- [用户](#customers)
- [支持的编译器](#supported-compilers)
- [集成](#integration)
- [CMake](#cmake)
- [包管理器](#package-managers)
- [Pkg-config](#pkg-config)
- [许可证](#license)
- [联系](#contact)
- [致谢](#thanks)
- [使用的第三方工具](#used-third-party-tools)
- [说明](#notes)
- [执行单元测试](#execute-unit-tests)
## 设计目标
现存的 [JSON](https://json.org) 库数不胜数,每个库都有其存在的理由。我们的类设定了以下设计目标:
- **直观的语法**。在 Python 等语言中,JSON 感觉像是一等数据类型。我们利用了现代 C++ 所有的运算符魔法来在你的代码中实现相同的感觉。看看[下面的例子](#examples),你就会明白我的意思。
- **极简集成**。我们的全部代码仅由一个头文件 [`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) 组成。就是这样。没有库文件,没有子项目,没有依赖项,没有复杂的构建系统。该类使用原生 C++11 编写。总而言之,一切都不应该需要调整你的编译器标志或项目设置。该库也包含在所有流行的[包管理器](https://json.nlohmann.me/integration/package_managers/)中。
- **严格测试**。我们的代码经过了大量的[单元测试](https://github.com/nlohmann/json/tree/develop/tests/src),覆盖了 [100%](https://coveralls.io/r/nlohmann/json) 的代码,包括所有异常行为。此外,我们使用 [Valgrind](https://valgrind.org) 和 [Clang Sanitizers](https://clang.llvm.org/docs/index.html) 进行了检查,确保没有内存泄漏。[Google OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/json) 还会对所有解析器进行 24/7 的模糊测试,目前实际上已经执行了数十亿次测试。为了保持高质量,该项目遵循 [Core Infrastructure Initiative (CII) 最佳实践](https://bestpractices.coreinfrastructure.org/projects/289)。请参阅[质量保证](https://json.nlohmann.me/community/quality_assurance)概述文档。
其他方面对我们来说没那么重要:
- **内存效率**。每个 JSON 对象都有开销,包括一个指针(union 的最大大小)和一个枚举元素(1 字节)。默认泛化使用以下 C++ 数据类型:`std::string` 用于字符串,`int64_t`、`uint64_t` 或 `double` 用于数字,`std::map` 用于对象,`std::vector` 用于数组,`bool` 用于布尔值。但是,你可以根据需要模板化泛化类 `basic_json`。
- **速度**。肯定有[更快的 JSON 库](https://github.com/miloyip/nativejson-benchmark#parsing-time)。但是,如果你的目标是通过添加单个头文件的 JSON 支持来加速开发,那么这个库就是你的不二之选。如果你知道如何使用 `std::vector` 或 `std::map`,那你已经准备好了。
更多信息请参阅[贡献指南](https://github.com/nlohmann/json/blob/master/.github/CONTRIBUTING.md#please-dont)。
## 支持
:question: 如果你有**问题**,请先检查 [**FAQ**](https://json.nlohmann.me/home/faq/) 或 [**Q&A**](https://github.com/nlohmann/json/discussions/categories/q-a) 部分是否已有解答。如果没有,请在那里[**提出新问题**](https://github.com/nlohmann/json/discussions/new)。
:books: 如果你想**了解更多**关于如何使用该库的信息,请查阅 [**README**](#examples) 的其余部分,查看[**代码示例**](https://github.com/nlohmann/json/tree/develop/docs/mkdocs/docs/examples),或浏览[**帮助页面**](https://json.nlohmann.me)。
:construction: 如果你想更好地理解 **API**,请查看 [**API 参考**](https://json.nlohmann.me/api/basic_json/) 或查看下面的快速参考。
:bug: 如果你发现了 **Bug**,请检查 [**FAQ**](https://json.nlohmann.me/home/faq/) 看它是否是已知问题或设计决定的结果。在[**创建新 issue**](https://github.com/nlohmann/json/issues/new/choose) 之前,也请查看 [**issue 列表**](https://github.com/nlohmann/json/issues)。请提供尽可能多的信息,以帮助我们理解和重现你的问题。
还有适用于文档浏览器 [Dash](https://kapeli.com/dash)、[Velocity](https://velocity.silverlakesoftware.com) 和 [Zeal](https://zealdocs.org) 的 [**docset**](https://github.com/Kapeli/Dash-User-Contributions/tree/master/docsets/JSON_for_Modern_C%2B%2B),其中包含完整的[文档](https://json.nlohmann.me)作为离线资源。
## 快速参考
- **构造函数** [basic_json](https://json.nlohmann.me/api/basic_json/basic_json), [array](https://json.nlohmann.me/api/basic_json/array), [binary](https://json.nlohmann.me/api/basic_json/binary), [object](https://json.nlohmann.me/api/basic_json/object)
- **对象检查**: [type](https://json.nlohmann.me/api/basic_json/type), [operator value_t](https://json.nlohmann.me/api/basic_json/operator_value_t), [type_name](https://json.nlohmann.me/api/basic_json/type_name), [is_primitive](https://json.nlohmann.me/api/basic_json/is_primitive), [is_structured](https://json.nlohmann.me/api/basic_json/is_structured), [is_null](https://json.nlohmann.me/api/basic_json/is_null), [is_boolean](https://json.nlohmann.me/api/basic_json/is_boolean), [is_number](https://json.nlohmann.me/api/basic_json/is_number), [is_number_integer](https://json.nlohmann.me/api/basic_json/is_number_integer), [is_number_unsigned](https://json.nlohmann.me/api/basic_json/is_number_unsigned), [is_number_float](https://json.nlohmann.me/api/basic_json/is_number_float), [is_object](https://json.nlohmann.me/api/basic_json/is_object), [is_array](https://json.nlohmann.me/api/basic_json/is_array), [is_string](https://json.nlohmann.me/api/basic_json/is_string), [is_binary](https://json.nlohmann.me/api/basic_json/is_binary), [is_discarded](https://json.nlohmann.me/api/basic_json/is_discarded)
- **值访问**: [get](https://json.nlohmann.me/api/basic_json/get), [get_to](https://json.nlohmann.me/api/basic_json/get_to), [get_ptr](https://json.nlohmann.me/api/basic_json/get_ptr), [get_ref](https://json.nlohmann.me/api/basic_json/get_ref), [operator ValueType](https://json.nlohmann.me/api/basic_json/operator_ValueType), [get_binary](https://json.nlohmann.me/api/basic_json/get_binary)
- **元素访问**: [at](https://json.nlohmann.me/api/basic_json/at), [operator[]](https://json.nlohmann.me/api/basic_json/operator[]), [value](https://json.nlohmann.me/api/basic_json/value), [front](https://json.nlohmann.me/api/basic_json/front), [back](https://json.nlohmann.me/api/basic_json/back)
- **查找**: [find](https://json.nlohmann.me/api/basic_json/find), [count](https://json.nlohmann.me/api/basic_json/count), [contains](https://json.nlohmann.me/api/basic_json/contains)
- **迭代器**: [begin](https://json.nlohmann.me/api/basic_json/begin), [cbegin](https://json.nlohmann.me/api/basic_json/cbegin), [end](https://json.nlohmann.me/api/basic_json/end), [cend](https://json.nlohmann.me/api/basic_json/cend), [rbegin](https://json.nlohmann.me/api/basic_json/rbegin), [rend](https://json.nlohmann.me/api/basic_json/rend), [crbegin](https://json.nlohmann.me/api/basic_json/crbegin), [crend](https://json.nlohmann.me/api/basic_json/crend), [items](https://json.nlohmann.me/api/basic_json/items)
- **容量**: [empty](https://json.nlohmann.me/api/basic_json/empty), [size](https://json.nlohmann.me/api/basic_json/size), [max_size](https://json.nlohmann.me/api/basic_json/max_size)
- **修改器**: [clear](https://json.nlohmann.me/api/basic_json/clear), [push_back](https://json.nlohmann.me/api/basic_json/push_back), [operator+=](https://json.nlohmann.me/api/basic_json/operator+=), [emplace_back](https://json.nlohmann.me/api/basic_json/emplace_back), [emplace](https://json.nlohmann.me/api/basic_json/emplace), [erase](https://json.nlohmann.me/api/basic_json/erase), [insert](https://json.nlohmann.me/api/basic_json/insert), [update](https://json.nlohmann.me/api/basic_json/update), [swap](https://json.nlohmann.me/api/basic_json/swap)
- **字典序比较运算符**: [operator==](https://json.nlohmann.me/api/basic_json/operator_eq), [operator!=](https://json.nlohmann.me/api/basic_json/operator_ne), [operator<](https://json.nlohmann.me/api/basic_json/operator_lt), [operator>](https://json.nlohmann.me/api/basic_json/operator_gt), [operator<=](https://json.nlohmann.me/api/basic_json/operator_le), [operator>=](https://json.nlohmann.me/api/basic_json/operator_ge), [operator<=>](https://json.nlohmann.me/api/basic_json/operator_spaceship)
- **序列化 / Dumping**: [dump](https://json.nlohmann.me/api/basic_json/dump)
- **反序列化 / 解析**: [parse](https://json.nlohmann.me/api/basic_json/parse), [accept](https://json.nlohmann.me/api/basic_json/accept), [sax_parse](https://json.nlohmann.me/api/basic_json/sax_parse)
- **JSON Pointer 函数**: [flatten](https://json.nlohmann.me/api/basic_json/flatten), [unflatten](https://json.nlohmann.me/api/basic_json/unflatten)
- **JSON Patch 函数**: [patch](https://json.nlohmann.me/api/basic_json/patch), [patch_inplace](https://json.nlohmann.me/api/basic_json/patch_inplace), [diff](https://json.nlohmann.me/api/basic_json/diff), [merge_patch](https://json.nlohmann.me/api/basic_json/merge_patch)
- **静态函数**: [meta](https://json.nlohmann.me/api/basic_json/meta), [get_allocator](https://json.nlohmann.me/api/basic_json/get_allocator)
- **二进制格式**: [from_bjdata](https://json.nlohmann.me/api/basic_json/from_bjdata), [from_bson](https://json.nlohmann.me/api/basic_json/from_bson), [from_cbor](https://json.nlohmann.me/api/basic_json/from_cbor), [from_msgpack](https://json.nlohmann.me/api/basic_json/from_msgpack), [from_ubjson](https://json.nlohmann.me/api/basic_json/from_ubjson), [to_bjdata](https://json.nlohmann.me/api/basic_json/to_bjdata), [to_bson](https://json.nlohmann.me/api/basic_json/to_bson), [to_cbor](https://json.nlohmann.me/api/basic_json/to_cbor), [to_msgpack](https://json.nlohmann.me/api/basic_json/to_msgpack), [to_ubjson](https://json.nlohmann.me/api/basic_json/to_ubjson)
- **非成员函数**: [operator<<](https://json.nlohmann.me/api/operator_ltlt/), [operator>>](https://json.nlohmann.me/api/operator_gtgt/), [to_string](https://json.nlohmann.me/api/basic_json/to_string)
- **字面量**: [operator""_json](https://json.nlohmann.me/api/operator_literal_json)
- **辅助类**: [std::hash<basic_json>](https://json.nlohmann.me/api/basic_json/std_hash),std::swap<basic_json>](https://json.nlohmann.me/api/basic_json/std_swap)
[**完整 API 文档**](https://json.nlohmann.me/api/basic_json/)
## 示例
这里有一些示例可以让你了解如何使用这个类。
除了下面的示例外,你可能还想:
→ 查看[文档](https://json.nlohmann.me/)\
→ 浏览[独立示例文件](https://github.com/nlohmann/json/tree/develop/docs/mkdocs/docs/examples)\
→ 阅读包含每个函数自包含示例的完整 [API 文档](https://json.nlohmann.me/api/basic_json/)
### 从文件读取 JSON
`json` 类提供了一个用于操作 JSON 值的 API。要通过读取 JSON 文件来创建 `json` 对象:
```
#include
#include
using json = nlohmann::json;
// ...
std::ifstream f("example.json");
json data = json::parse(f);
```
如果使用模块(通过 `NLOHMANN_JSON_BUILD_MODULES` 启用),此示例变为:
```
import std;
import nlohmann.json;
using json = nlohmann::json;
// ...
std::ifstream f("example.json");
json data = json::parse(f);
```
### 从 JSON 字面量创建 `json` 对象
假设你想在文件中硬编码这个 JSON 字面量值,作为一个 `json` 对象:
```
{
"pi": 3.141,
"happy": true
}
```
有各种选项:
```
// Using (raw) string literals and json::parse
json ex1 = json::parse(R"(
{
"pi": 3.141,
"happy": true
}
)");
// Using user-defined (raw) string literals
using namespace nlohmann::literals;
json ex2 = R"(
{
"pi": 3.141,
"happy": true
}
)"_json;
// Using initializer lists
json ex3 = {
{"happy", true},
{"pi", 3.141},
};
```
### JSON 作为一等数据类型
这里有一些示例可以让你了解如何使用这个类。
假设你想创建 JSON 对象
```
{
"pi": 3.141,
"happy": true,
"name": "Niels",
"nothing": null,
"answer": {
"everything": 42
},
"list": [1, 0, 2],
"object": {
"currency": "USD",
"value": 42.99
}
}
```
使用这个库,你可以这样写:
```
// create an empty structure (null)
json j;
// add a number stored as double (note the implicit conversion of j to an object)
j["pi"] = 3.141;
// add a Boolean stored as bool
j["happy"] = true;
// add a string stored as std::string
j["name"] = "Niels";
// add another null object by passing nullptr
j["nothing"] = nullptr;
// add an object inside the object
j["answer"]["everything"] = 42;
// add an array stored as std::vector (using an initializer list)
j["list"] = { 1, 0, 2 };
// add another object (using an initializer list of pairs)
j["object"] = { {"currency", "USD"}, {"value", 42.99} };
// instead, you could also write (which looks very similar to the JSON above)
json j2 = {
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
{"nothing", nullptr},
{"answer", {
{"everything", 42}
}},
{"list", {1, 0, 2}},
{"object", {
{"currency", "USD"},
{"value", 42.99}
}}
};
```
请注意,在所有这些情况下,你永远不需要“告诉”编译器你想使用哪种 JSON 值类型。如果你想明确表达或处理一些边缘情况,函数 [`json::array()`](https://json.nlohmann.me/api/basic_json/array/) 和 [`json::object()`](https://json.nlohmann.me/api/basic_json/object/) 会有所帮助:
```
// a way to express the empty array []
json empty_array_explicit = json::array();
// ways to express the empty object {}
json empty_object_implicit = json({});
json empty_object_explicit = json::object();
// a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]]
json array_not_object = json::array({ {"currency", "USD"}, {"value", 42.99} });
```
### 序列化 / 反序列化
#### 与字符串相互转换
你可以通过在字符串字面量后附加 `_json` 来创建 JSON 值(反序列化):
```
// create object from string literal
json j = "{ \"happy\": true, \"pi\": 3.141 }"_json;
// or even nicer with a raw string literal
auto j2 = R"(
{
"happy": true,
"pi": 3.141
}
)"_json;
```
请注意,如果不附加 `_json` 后缀,传递的字符串字面量将不会被解析,而只是用作 JSON 字符串值。也就是说,`json j = "{ \"happy\": true, \"pi\": 3.141 }"` 只会存储字符串 `"{ "happy": true, "pi": 3.141 }"` 而不是解析实际的对象。
应该使用 `using namespace nlohmann::literals;` 将字符串字面量引入作用域(见 [`json::parse()`](https://json.nlohmann.me/api/operator_literal_json/))。
上面的示例也可以使用 [`json::parse()`](https://json.nlohmann.me/api/basic_json/parse/) 显式表达:
```
// parse explicitly
auto j3 = json::parse(R"({"happy": true, "pi": 3.141})");
```
你还可以获取 JSON 值的字符串表示(序列化):
```
// explicit conversion to string
std::string s = j.dump(); // {"happy":true,"pi":3.141}
// serialization with pretty printing
// pass in the amount of spaces to indent
std::cout << j.dump(4) << std::endl;
// {
// "happy": true,
// "pi": 3.141
// }
```
注意序列化和赋值的区别:
```
// store a string in a JSON value
json j_string = "this is a string";
// retrieve the string value
auto cpp_string = j_string.get();
// retrieve the string value (alternative when a variable already exists)
std::string cpp_string2;
j_string.get_to(cpp_string2);
// retrieve the serialized value (explicit JSON serialization)
std::string serialized_string = j_string.dump();
// output of original string
std::cout << cpp_string << " == " << cpp_string2 << " == " << j_string.get() << '\n';
// output of serialized value
std::cout << j_string << " == " << serialized_string << std::endl;
```
[`.dump()`](https://json.nlohmann.me/api/basic_json/dump/) 返回最初存储的字符串值。
请注意,该库仅支持 UTF-8。当你在库中存储不同编码的字符串时,调用 [`dump()`](https://json.nlohmann.me/api/basic_json/dump/) 可能会抛出异常,除非使用 `json::error_handler_t::replace` 或 `json::error_handler_t::ignore` 作为错误处理器。
#### 与流(例如文件、字符串流)相互转换
你也可以使用流进行序列化和反序列化:
```
// deserialize from standard input
json j;
std::cin >> j;
// serialize to standard output
std::cout << j;
// the setw manipulator was overloaded to set the indentation for pretty printing
std::cout << std::setw(4) << j << std::endl;
```
这些运算符适用于 `std::istream` 或 `std::ostream` 的任何子类。这是使用文件的相同示例:
```
// read a JSON file
std::ifstream i("file.json");
json j;
i >> j;
// write prettified JSON to another file
std::ofstream o("pretty.json");
o << std::setw(4) << j << std::endl;
```
请注意,为此用例设置 `failbit` 的异常位是不合适的。由于使用了 `noexcept` 说明符,这将导致程序终止。
#### 从迭代器范围读取
你也可以从迭代器范围解析 JSON;也就是说,从任何可由迭代器访问的容器,其 `value_type` 是 1、2 或 4 字节的整型,将分别被解释为 UTF-8、UTF-16 和 UTF-32。例如,`std::vector` 或 `std::list`:
```
std::vector v = {'t', 'r', 'u', 'e'};
json j = json::parse(v.begin(), v.end());
```
你可以保留迭代器用于范围 [begin, end):
```
std::vector v = {'t', 'r', 'u', 'e'};
json j = json::parse(v);
```
#### 自定义数据源
由于解析函数接受任意迭代器范围,你可以通过实现 `LegacyInputIterator` 概念来提供自己的数据源。
```
struct MyContainer {
void advance();
const char& get_current();
};
struct MyIterator {
using difference_type = std::ptrdiff_t;
using value_type = char;
using pointer = const char*;
using reference = const char&;
using iterator_category = std::input_iterator_tag;
MyIterator& operator++() {
target->advance();
return *this;
}
bool operator!=(const MyIterator& rhs) const {
return rhs.target != target;
}
reference operator*() const {
return target->get_current();
}
MyContainer* target = nullptr;
};
MyIterator begin(MyContainer& tgt) {
return MyIterator{&tgt};
}
MyIterator end(const MyContainer&) {
return {};
}
void foo() {
MyContainer c;
json j = json::parse(c);
}
```
#### SAX 接口
该库使用类似 SAX 的接口,具有以下函数:
```
// called when null is parsed
bool null();
// called when a boolean is parsed; value is passed
bool boolean(bool val);
// called when a signed or unsigned integer number is parsed; value is passed
bool number_integer(number_integer_t val);
bool number_unsigned(number_unsigned_t val);
// called when a floating-point number is parsed; value and original string is passed
bool number_float(number_float_t val, const string_t& s);
// called when a string is parsed; value is passed and can be safely moved away
bool string(string_t& val);
// called when a binary value is parsed; value is passed and can be safely moved away
bool binary(binary_t& val);
// called when an object or array begins or ends, resp. The number of elements is passed (or -1 if not known)
bool start_object(std::size_t elements);
bool end_object();
bool start_array(std::size_t elements);
bool end_array();
// called when an object key is parsed; value is passed and can be safely moved away
bool key(string_t& val);
// called when a parse error occurs; byte position, the last token, and an exception is passed
bool parse_error(std::size_t position, const std::string& last_token, const detail::exception& ex);
```
每个函数的返回值决定是否继续解析。
要实现你自己的 SAX 处理器,请按以下步骤操作:
1. 在类中实现 SAX 接口。你可以使用类 `nlohmann::json_sax` 作为基类,但你也可以使用任何实现了上述函数且为 public 的类。
2. 创建你的 SAX 接口类的对象,例如 `my_sax`。
3. 调用 `bool json::sax_parse(input, &my_sax)`;其中第一个参数可以是任何输入,如字符串或输入流,第二个参数是指向你的 SAX 接口的指针。
请注意,`sax_parse` 函数仅返回一个 `bool`,指示最后执行的 SAX 事件的结果。它不返回 `json` 值——你可以自行决定如何处理 SAX 事件。此外,在发生解析错误时不会抛出异常——你需要自行决定如何处理传递给 `parse_error` 实现的异常对象。在内部,SAX 接口用于 DOM 解析器(类 `json_sax_dom_parser`)以及接受器(`json_sax_acceptor`),参见文件 [`json_sax.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/detail/input/json_sax.hpp)。
### 类似 STL 的访问方式
我们将 JSON 类设计为行为类似于 STL 容器。事实上,它满足了 [**ReversibleContainer**](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) 要求。
```
// create an array using push_back
json j;
j.push_back("foo");
j.push_back(1);
j.push_back(true);
// also use emplace_back
j.emplace_back(1.78);
// iterate the array
for (json::iterator it = j.begin(); it != j.end(); ++it) {
std::cout << *it << '\n';
}
// range-based for
for (auto& element : j) {
std::cout << element << '\n';
}
// getter/setter
const auto tmp = j[0].get();
j[1] = 42;
bool foo = j.at(2);
// comparison
j == R"(["foo", 1, true, 1.78])"_json; // true
// other stuff
j.size(); // 4 entries
j.empty(); // false
j.type(); // json::value_t::array
j.clear(); // the array is empty again
// convenience type checkers
j.is_null();
j.is_boolean();
j.is_number();
j.is_object();
j.is_array();
j.is_string();
// create an object
json o;
o["foo"] = 23;
o["bar"] = false;
o["baz"] = 3.141;
// also use emplace
o.emplace("weather", "sunny");
// special iterator member functions for objects
for (json::iterator it = o.begin(); it != o.end(); ++it) {
std::cout << it.key() << " : " << it.value() << "\n";
}
// the same code as range for
for (auto& el : o.items()) {
std::cout << el.key() << " : " << el.value() << "\n";
}
// even easier with structured bindings (C++17)
for (auto& [key, value] : o.items()) {
std::cout << key << " : " << value << "\n";
}
// find an entry
if (o.contains("foo")) {
// there is an entry with key "foo"
}
// or via find and an iterator
if (o.find("foo") != o.end()) {
// there is an entry with key "foo"
}
// or simpler using count()
int foo_present = o.count("foo"); // 1
int fob_present = o.count("fob"); // 0
// delete an entry
o.erase("foo");
```
### 从 STL 容器转换
任何序列容器(`std::array`、`std::vector`、`std::deque`、`std::forward_list`、`std::list`),只要其值可用于构造 JSON 值(例如,整数、浮点数、布尔值、字符串类型,或本节中描述的 STL 容器),都可用于创建 JSON 数组。对于类似的关联容器(`std::set`、`std::multiset`、`std::unordered_set`、`std::unordered_multiset`)也是如此,但在这些情况下,数组元素的顺序取决于元素在各自 STL 容器中的排序方式。
```
std::vector c_vector {1, 2, 3, 4};
json j_vec(c_vector);
// [1, 2, 3, 4]
std::deque c_deque {1.2, 2.3, 3.4, 5.6};
json j_deque(c_deque);
// [1.2, 2.3, 3.4, 5.6]
std::list c_list {true, true, false, true};
json j_list(c_list);
// [true, true, false, true]
std::forward_list c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543};
json j_flist(c_flist);
// [12345678909876, 23456789098765, 34567890987654, 45678909876543]
std::array c_array {{1, 2, 3, 4}};
json j_array(c_array);
// [1, 2, 3, 4]
std::set c_set {"one", "two", "three", "four", "one"};
json j_set(c_set); // only one entry for "one" is used
// ["four", "one", "three", "two"]
std::unordered_set c_uset {"one", "two", "three", "four", "one"};
json j_uset(c_uset); // only one entry for "one" is used
// maybe ["two", "three", "four", "one"]
std::multiset c_mset {"one", "two", "one", "four"};
json j_mset(c_mset); // both entries for "one" are used
// maybe ["one", "two", "one", "four"]
std::unordered_multiset c_umset {"one", "two", "one", "four"};
json j_umset(c_umset); // both entries for "one" are used
// maybe ["one", "two", "one", "four"]
```
同样,任何关联键值容器(`std::map`、`std::multimap`、`std::unordered_map`、`std::unordered_multimap`),只要其键可构造 `std::string` 且其值可用于构造 JSON 值(见上面的示例),都可用于创建 JSON 对象。请注意,对于 multimap,JSON 对象中仅使用一个键,其值取决于 STL 容器的内部顺序。
```
std::map c_map { {"one", 1}, {"two", 2}, {"three", 3} };
json j_map(c_map);
// {"one": 1, "three": 3, "two": 2 }
std::unordered_map c_umap { {"one", 1.2}, {"two", 2.3}, {"three", 3.4} };
json j_umap(c_umap);
// {"one": 1.2, "two": 2.3, "three": 3.4}
std::multimap c_mmap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
json j_mmap(c_mmap); // only one entry for key "three" is used
// maybe {"one": true, "two": true, "three": true}
std::unordered_multimap c_ummap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
json j_ummap(c_ummap); // only one entry for key "three" is used
// maybe {"one": true, "two": true, "three": true}
```
### JSON Pointer 和 JSON Patch
该库支持 **JSON Pointer** ([RFC 6901](https://tools.ietf.org/html/rfc6901)) 作为寻址结构化值的替代方法。在此基础上,**JSON Patch** ([RFC 6902](https://tools.ietf.org/html/rfc6902)) 允许描述两个 JSON 值之间的差异——实际上允许 Unix 中已知的 patch 和 diff 操作。
```
// a JSON value
json j_original = R"({
"baz": ["one", "two", "three"],
"foo": "bar"
})"_json;
// access members with a JSON pointer (RFC 6901)
j_original["/baz/1"_json_pointer];
// "two"
// a JSON patch (RFC 6902)
json j_patch = R"([
{ "op": "replace", "path": "/baz", "value": "boo" },
{ "op": "add", "path": "/hello", "value": ["world"] },
{ "op": "remove", "path": "/foo"}
])"_json;
// apply the patch
json j_result = j_original.patch(j_patch);
// {
// "baz": "boo",
// "hello": ["world"]
// }
// calculate a JSON patch from two JSON values
json::diff(j_result, j_original);
// [
// { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] },
// { "op": "remove","path": "/hello" },
// { "op": "add", "path": "/foo", "value": "bar" }
// ]
```
### JSON Merge Patch
该库支持 **JSON Merge Patch** ([RFC 7386](https://tools.ietf.org/html/rfc7386)) 作为一种 patch 格式。它不是使用 JSON Pointer(见上文)来指定要操作的值,而是使用一种紧密模仿被修改文档的语法来描述更改。
```
// a JSON value
json j_document = R"({
"a": "b",
"c": {
"d": "e",
"f": "g"
}
})"_json;
// a patch
json j_patch = R"({
"a":"z",
"c": {
"f": null
}
})"_json;
// apply the patch
j_document.merge_patch(j_patch);
// {
// "a": "z",
// "c": {
// "d": "e"
// }
// }
```
### 隐式转换
支持的类型可以隐式转换为 JSON 值。
建议**不要使用**从 JSON 值**出发**的隐式转换。
你可以[在此处](https://www.github.com/nlohmann/json/issues/958)找到有关此建议的更多详细信息。
你可以通过在包含 `json.hpp` 头文件之前将 `JSON_USE_IMPLICIT_CONVERSIONS` 定义为 `0` 来关闭隐式转换。使用 CMake 时,你也可以通过将选项 `JSON_ImplicitConversions` 设置为 `OFF` 来实现此目的。
```
// strings
std::string s1 = "Hello, world!";
json js = s1;
auto s2 = js.get();
// NOT RECOMMENDED
std::string s3 = js;
std::string s4;
s4 = js;
// Booleans
bool b1 = true;
json jb = b1;
auto b2 = jb.get();
// NOT RECOMMENDED
bool b3 = jb;
bool b4;
b4 = jb;
// numbers
int i = 42;
json jn = i;
auto f = jn.get();
// NOT RECOMMENDED
double f2 = jb;
double f3;
f3 = jb;
// etc.
```
请注意,`char` 类型不会自动转换为 JSON 字符串,而是转换为整数数字。必须显式指定到字符串的转换:
```
char ch = 'A'; // ASCII value 65
json j_default = ch; // stores integer number 65
json j_string = std::string(1, ch); // stores string "A"
```
### 任意类型转换
每种类型都可以序列化为 JSON,不仅仅是 STL 容器和标量类型。通常,你会这样做:
```
namespace ns {
// a simple struct to model a person
struct person {
std::string name;
std::string address;
int age;
};
}
ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};
// convert to JSON: copy each value into the JSON object
json j;
j["name"] = p.name;
j["address"] = p.address;
j["age"] = p.age;
// ...
// convert from JSON: copy each value from the JSON object
ns::person p {
j["name"].get(),
j["address"].get(),
j["age"].get()
};
```
这行得通,但这有很多样板代码……幸运的是,有一种更好的方法:
```
// create a person
ns::person p {"Ned Flanders", "744 Evergreen Terrace", 60};
// conversion: person -> json
json j = p;
std::cout << j << std::endl;
// {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"}
// conversion: json -> person
auto p2 = j.get();
// that's it
assert(p == p2);
```
#### 基本用法
要使这适用于你的某种类型,你只需要提供两个函数:
```
using json = nlohmann::json;
namespace ns {
void to_json(json& j, const person& p) {
j = json{{"name", p.name}, {"address", p.address}, {"age", p.age}};
}
void from_json(const json& j, person& p) {
j.at("name").get_to(p.name);
j.at("address").get_to(p.address);
j.at("age").get_to(p.age);
}
} // namespace ns
```
就是这样!当使用你的类型调用 `json` 构造函数时,你的自定义 `to_json` 方法将被自动调用。
同样,当调用 `get()` 或 `get_to(your_type&)` 时,将调用 `from_json` 方法。
一些重要的事情:
- 这些方法**必须**位于你类型的命名空间中(可以是全局命名空间),否则库将无法找到它们(在这个例子中,它们位于命名空间 `ns` 中,即定义 `person` 的地方)。
- 这些方法**必须**在你使用这些转换的任何地方都可用(例如,必须包含正确的头文件)。否则请查看 [issue 1108](https://github.com/nlohmann/json/issues/1108) 可能出现的错误。
- 使用 `get()` 时,`your_type` **必须**是 [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible)。(稍后描述了一种绕过此要求的方法。)
- 在函数 `from_json` 中,使用函数 [`at()`](https://json.nlohmann.me/api/basic_json/at/) 访问对象值,而不是 `operator[]`。如果键不存在,`at` 会抛出一个你可以处理的异常,而 `operator[]` 则表现出未定义的行为。
- 你不需要为 `std::vector` 等 STL 类型添加序列化器或反序列化器:库已经实现了这些。
#### 使用宏简化你的生活
如果你只是想序列化/反序列化一些结构体,`to_json`/`from_json` 函数可能会有很多样板代码。有 [**几个宏**](https://json.nlohmann.me/features/arbitrary_types/#simplify-your-life-with-macros) 可以让你的生活更轻松,只要你 (1) 想要使用 JSON 对象作为序列化,并且 (2) 想要在该对象中使用成员变量名称作为对象键。
选择哪个宏取决于是否需要访问私有成员变量、是否需要反序列化、缺失值应该产生错误还是应该被默认值替换,以及是否使用了派生类。请参阅[此概述以为你的用例选择正确的宏](https://json.nlohmann.me/api/macros/#serializationdeserialization-macros)。
##### 宏使用示例
上面 `person` 结构体的 `to_json`/`from_json` 函数可以用 [`NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`](https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/) 创建。在所有宏中,第一个参数是类/结构体的名称,其余所有参数命名成员。
```
namespace ns {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age)
}
```
这是另一个包含私有成员的示例,其中需要 [`NLOHMANN_DEFINE_TYPE_INTRUSIVE`](https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/):
```
namespace ns {
class address {
private:
std::string street;
int housenumber;
int postcode;
public:
NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode)
};
}
```
#### 如何转换第三方类型?
这需要稍微高级一点的技术。但首先,让我们看看这种转换机制是如何工作的:
该库使用 **JSON Serializers** 将类型转换为 JSON。
`nlohmann::json` 的默认序列化器是 `nlohmann::adl_serializer`(ADL 表示 [Argument-Dependent Lookup](https://en.cppreference.com/w/cpp/language/adl))。
它的实现方式如下(简化版):
```
template
struct adl_serializer {
static void to_json(json& j, const T& value) {
// calls the "to_json" method in T's namespace
}
static void from_json(const json& j, T& value) {
// same thing, but with the "from_json" method
}
};
```
当你能够控制类型的命名空间时,这个序列化器工作得很好。但是,`boost::optional` 或 `std::filesystem::path` (C++17) 呢?劫持 `boost` 命名空间是非常糟糕的,而且向 `std` 添加除模板特化以外的东西是非法的……
为了解决这个问题,你需要向 `nlohmann` 命名空间添加 `adl_serializer` 的特化,这是一个例子:
```
// partial specialization (full specialization works too)
namespace nlohmann {
template
struct adl_serializer> {
static void to_json(json& j, const boost::optional& opt) {
if (opt == boost::none) {
j = nullptr;
} else {
j = *opt; // this will call adl_serializer::to_json which will
// find the free function to_json in T's namespace!
}
}
static void from_json(const json& j, boost::optional& opt) {
if (j.is_null()) {
opt = boost::none;
} else {
opt = j.get(); // same as above, but with
// adl_serializer::from_json
}
}
};
}
```
#### 如何为不可默认构造/不可复制的类型使用 `get()`?
如果你的类型是 [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible),则有办法。你也需要特化 `adl_serializer`,但使用特殊的 `from_json` 重载:
```
struct move_only_type {
move_only_type() = delete;
move_only_type(int ii): i(ii) {}
move_only_type(const move_only_type&) = delete;
move_only_type(move_only_type&&) = default;
int i;
};
namespace nlohmann {
template <>
struct adl_serializer {
// note: the return type is no longer 'void', and the method only takes
// one argument
static move_only_type from_json(const json& j) {
return {j.get()};
}
// Here's the catch! You must provide a to_json method! Otherwise, you
// will not be able to convert move_only_type to json, since you fully
// specialized adl_serializer on that type
static void to_json(json& j, move_only_type t) {
j = t.i;
}
};
}
```
#### 我可以编写自己的序列化器吗?(高级用法)
可以。你可能想查看测试套件中的 [`unit-udt.cpp`](https://github.com/nlohmann/json/blob/develop/tests/src/unit-udt.cpp) 以获取一些示例。
如果你编写自己的序列化器,你需要做几件事:
- 使用与 `nlohmann::json` 不同的 `basic_json` 别名(`basic_json` 的最后一个模板参数是 `JSONSerializer`)
- 在所有 `to_json`/`from_json` 方法中使用你的 `basic_json` 别名(或模板参数)
- 需要时使用 `nlohmann::to_json` 和 `nlohmann::from_json` 以利用 ADL
这是一个没有简化的示例,它只接受大小 <= 32 的类型,并使用 ADL。
```
// You should use void as a second template argument
// if you don't need compile-time checks on T
template::type>
struct less_than_32_serializer {
template
static void to_json(BasicJsonType& j, T value) {
// we want to use ADL, and call the correct to_json overload
using nlohmann::to_json; // this method is called by adl_serializer,
// this is where the magic happens
to_json(j, value);
}
template
static void from_json(const BasicJsonType& j, T& value) {
// same thing here
using nlohmann::from_json;
from_json(j, value);
}
};
```
重新实现序列化器时要**非常**小心,如果不注意可能会导致栈溢出:
```
template
struct bad_serializer
{
template
static void to_json(BasicJsonType& j, const T& value) {
// this calls BasicJsonType::json_serializer::to_json(j, value)
// if BasicJsonType::json_serializer == bad_serializer ... oops!
j = value;
}
template
static void to_json(const BasicJsonType& j, T& value) {
// this calls BasicJsonType::json_serializer::from_json(j, value)
// if BasicJsonType::json_serializer == bad_serializer ... oops!
value = j.get(); // oops!
}
};
```
### 特化枚举转换
默认情况下,枚举值作为整数序列化为 JSON。在某些情况下,这可能会导致不良行为。如果在将数据序列化为 JSON 后修改或重新排序枚举,则稍后反序列化的 JSON 数据可能是未定义的或与最初预期的枚举值不同。
可以更精确地指定给定枚举如何映射到 JSON 和从 JSON 映射,如下所示:
```
// example enum type declaration
enum TaskState {
TS_STOPPED,
TS_RUNNING,
TS_COMPLETED,
TS_INVALID=-1,
};
// map TaskState values to JSON as strings
NLOHMANN_JSON_SERIALIZE_ENUM( TaskState, {
{TS_INVALID, nullptr},
{TS_STOPPED, "stopped"},
{TS_RUNNING, "running"},
{TS_COMPLETED, "completed"},
})
```
`NLOHMANN_JSON_SERIALIZE_ENUM()` 宏为 `TaskState` 类型声明了一组 `to_json()` / `from_json()` 函数,同时避免了重复和样板序列化代码。
**用法:**
```
// enum to JSON as string
json j = TS_STOPPED;
assert(j == "stopped");
// json string to enum
json j3 = "running";
assert(j3.get() == TS_RUNNING);
// undefined json value to enum (where the first map entry above is the default)
json jPi = 3.14;
assert(jPi.get() == TS_INVALID);
```
就像上面的[任意类型转换](()` 时,未定义的 JSON 值将默认为你映射中指定的第一对。请仔细选择此默认对。
- 如果在映射中多次指定枚举或 JSON 值,则在转换为 JSON 或从 JSON 转换时,将返回从映射顶部开始的第一个匹配项。
### 二进制格式 (BSON, CBOR, MessagePack, UBJSON, 以及 BJData)
尽管 JSON 是一种无处不在的数据格式,但它并不是一种非常紧凑的格式,不适合数据交换,例如通过网络。因此,该库支持 [BSON](https://bsonspec.org) (Binary JSON)、[CBOR](https://cbor.io) (Concise Binary Object Representation)、[MessagePack](https://msgpack.org)、[UBJSON](https://ubjson.org) (Universal Binary JSON Specification) 和 [BJData](https://neurojson.org/bjdata) (Binary JData),以有效地将 JSON 值编码为字节向量并解码此类向量。
```
// create a JSON value
json j = R"({"compact": true, "schema": 0})"_json;
// serialize to BSON
std::vector v_bson = json::to_bson(j);
// 0x1B, 0x00, 0x00, 0x00, 0x08, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x00, 0x01, 0x10, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
// roundtrip
json j_from_bson = json::from_bson(v_bson);
// serialize to CBOR
std::vector v_cbor = json::to_cbor(j);
// 0xA2, 0x67, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0xF5, 0x66, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x00
// roundtrip
json j_from_cbor = json::from_cbor(v_cbor);
// serialize to MessagePack
std::vector v_msgpack = json::to_msgpack(j);
// 0x82, 0xA7, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0xC3, 0xA6, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x00
// roundtrip
json j_from_msgpack = json::from_msgpack(v_msgpack);
// serialize to UBJSON
std::vector v_ubjson = json::to_ubjson(j);
// 0x7B, 0x69, 0x07, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x54, 0x69, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x69, 0x00, 0x7D
// roundtrip
json j_from_ubjson = json::from_ubjson(v_ubjson);
```
该库还支持来自 BSON、CBOR(字节字符串)和 MessagePack(bin、ext、fixext)的二进制类型。默认情况下,它们存储为 `std::vector` 以便在库外处理。
```
// CBOR byte string with payload 0xCAFE
std::vector v = {0x42, 0xCA, 0xFE};
// read value
json j = json::from_cbor(v);
// the JSON value has type binary
j.is_binary(); // true
// get reference to stored binary value
auto& binary = j.get_binary();
// the binary value has no subtype (CBOR has no binary subtypes)
binary.has_subtype(); // false
// access std::vector member functions
binary.size(); // 2
binary[0]; // 0xCA
binary[1]; // 0xFE
// set subtype to 0x10
binary.set_subtype(0x10);
// serialize to MessagePack
auto cbor = json::to_msgpack(j); // 0xD5 (fixext2), 0x10, 0xCA, 0xFE
```
## 用户
该库被用于多个项目、应用程序、操作系统等。下面的列表并不详尽,而是互联网搜索的结果。如果你知道该库的其他用户,请告诉我,参见[联系方式](#contact)。
[](https://json.nlohmann.me/home/customers/)
## 支持的编译器
尽管已经是 2026 年,但对 C++11 的支持仍然有些稀少。目前,已知以下编译器可以工作:
- GCC 4.8 - 14.2 (及可能的更高版本)
- Clang 3.4 - 21.0 (及可能的更高版本)
- Apple Clang 9.1 - 16.0 (及可能的更高版本)
- Intel C++ Compiler 17.0.2 (及可能的更高版本)
- Nvidia CUDA Compiler 11.0.221 (及可能的更高版本)
- Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (及可能的更高版本)
- Microsoft Visual C++ 2017 / Build Tools 15.5.180.51428 (及可能的更高版本)
- Microsoft Visual C++ 2019 / Build Tools 16.3.1+1def00d3d (及可能的更高版本)
- Microsoft Visual C++ 2022 / Build Tools 19.30.30709.0 (及可能的更高版本)
我很乐意了解其他编译器/版本。
请注意:
- GCC 4.8 有一个 bug [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824):多行原始字符串不能作为宏的参数。不要在此编译器的宏中直接使用多行原始字符串。
- Android 默认使用非常旧的编译器和 C++ 库。要解决此问题,请将以下内容添加到你的 `Application.mk` 中。这将切换到 LLVM C++ 库、Clang 编译器,并启用默认禁用的 C++11 和其他功能。
APP_STL := c++_shared
NDK_TOOLCHAIN_VERSION := clang3.6
APP_CPPFLAGS += -frtti -fexceptions
代码可以使用 [Android NDK](https://developer.android.com/ndk/index.html?hl=ml) Revision 9 - 11(及可能的更高版本)和 [CrystaX's Android NDK](https://www.crystax.net/en/android/ndk) 版本 10 成功编译。
- 对于在 MinGW 或 Android SDK 上运行的 GCC,可能会出现错误 `'to_string' is not a member of 'std'`(或类似地,对于 `strtod` 或 `strtof`)。请注意,这不是代码的问题,而是编译器本身的问题。在 Android 上,请参阅上文以使用更新的环境进行构建。对于 MinGW,请参阅[此站点](https://tehsausage.com/mingw-to-string)和[此讨论](https://github.com/nlohmann/json/issues/136)以获取有关如何修复此 bug 的信息。对于使用 `APP_STL := gnustl_static` 的 Android NDK,请参阅[此讨论](https://github.com/nlohmann/json/issues/219)。
- 不支持的 GCC 和 Clang 版本会被 `#error` 指令拒绝。这可以通过定义 `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK` 来关闭。请注意,在这种情况下,你不能指望获得支持。
请参阅 CI 中用于检查库的编译器的[质量保证](https://json.nlohmann.me/community/quality_assurance)页面。
## 集成
[`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) 是 `single_include/nlohmann` 中或[此处发布](https://github.com/nlohmann/json/releases)的唯一必需文件。你需要添加
```
#include
// for convenience
using json = nlohmann::json;
```
到你想要处理 JSON 的文件中,并设置必要的开关以启用 C++11(例如,对于 GCC 和 Clang 使用 `-std=c++11`)。
你还可以使用文件 [`include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/json_fwd.hpp) 进行前向声明。可以通过设置 `-DJSON_MultipleHeaders=ON` 来实现 `json_fwd.hpp` 的安装(作为 cmake 安装步骤的一部分)。
### CMake
你还可以在 CMake 中使用 `nlohmann_json::nlohmann_json` 接口目标。此目标为 `INTERFACE_INCLUDE_DIRECTORIES` 填充适当的使用要求,以指向适当的包含目录,并为必要的 C++11 标志填充 `INTERFACE_COMPILE_FEATURES`。
#### 外部
要在 CMake 项目中使用此库,你可以使用 `find_package()` 直接定位它,并使用生成的包配置中的命名空间导入目标:
```
# CMakeLists.txt
find_package(nlohmann_json 3.12.0 REQUIRED)
...
add_library(foo ...)
...
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)
```
包配置文件 `nlohmann_jsonConfig.cmake` 可以从安装树直接使用,也可以直接从构建树中使用。
#### 嵌入
要将库直接嵌入到现有的 CMake 项目中,请将整个源代码树放在子目录中,并在你的 `CMakeLists.txt` 文件中调用 `add_subdirectory()`:
```
# Typically you don't care so much for a third party library's tests to be
# run from your own project's code.
set(JSON_BuildTests OFF CACHE INTERNAL "")
# If you only include this third party in PRIVATE source files, you do not
# need to install it when your main project gets installed.
# set(JSON_Install OFF CACHE INTERNAL "")
# Don't use include(nlohmann_json/CMakeLists.txt) since that carries with it
# unintended consequences that will break the build. It's generally
# discouraged (although not necessarily well documented as such) to use
# include(...) for pulling in other CMake projects anyways.
add_subdirectory(nlohmann_json)
...
add_library(foo ...)
...
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)
```
##### 嵌入 (FetchContent)
自 CMake v3.11 起,
[FetchContent](https://cmake.org/cmake/help/v3.11/module/FetchContent.html) 可
用于在配置时自动下载作为依赖项的发布版本。
示例:
```
include(FetchContent)
FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.12.0/json.tar.xz)
FetchContent_MakeAvailable(json)
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)
```
**注意**:建议使用上述 URL 方法,该方法从 3.10.0 版本开始支持。有关更多信息,请参阅
。
#### 同时支持两者
要允许你的项目支持外部提供的或嵌入的 JSON 库,你可以使用类似于以下的模式:
```
# Top level CMakeLists.txt
project(FOO)
...
option(FOO_USE_EXTERNAL_JSON "Use an external JSON library" OFF)
...
add_subdirectory(thirdparty)
...
add_library(foo ...)
...
# Note that the namespaced target will always be available regardless of the
# import method
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)
```
```
# thirdparty/CMakeLists.txt
...
if(FOO_USE_EXTERNAL_JSON)
find_package(nlohmann_json 3.12.0 REQUIRED)
else()
set(JSON_BuildTests OFF CACHE INTERNAL "")
add_subdirectory(nlohmann_json)
endif()
...
```
`thirdparty/nlohmann_json` 是此源代码树的完整副本。
### 包管理器
使用你喜欢的[**包管理器**](https://json.nlohmann.me/integration/package_managers/)来使用该库。
-
[**Homebrew**](https://json.nlohmann.me/integration/package_managers/#homebrew) `nlohmann-json`
-
[**Meson**](https://json.nlohmann.me/integration/package_managers/#meson) `nlohmann_json`
-
[**Bazel**](https://json.nlohmann.me/integration/package_managers/#bazel) `nlohmann_json`
-
[**Conan**](https://json.nlohmann.me/integration/package_managers/#conan) `nlohmann_json`
-
[**Spack**](https://json.nlohmann.me/integration/package_managers/#spack) `nlohmann-json`
- [**Hunter**](https://json.nlohmann.me/integration/package_managers/#hunter) `nlohmann_json`
-
[**vcpkg**](https://json.nlohmann.me/integration/package_managers/#vcpkg) `nlohmann-json`
- [**cget**](https://json.nlohmann.me/integration/package_managers/#cget) `nlohmann/json`
-
[**Swift Package Manager**](https://json.nlohmann.me/integration/package_managers/#swift-package-manager) `nlohmann/json`
-
[**Nuget**](https://json.nlohmann.me/integration/package_managers/#nuget) `nlohmann.json`
-
[**Conda**](https://json.nlohmann.me/integration/package_managers/#conda) `nlohmann_json`
-
[**MacPorts**](https://json.nlohmann.me/integration/package_managers/#macports) `nlohmann-json`
-
[**cpm.cmake**](https://json.nlohmann.me/integration/package_managers/#cpmcmake) `gh:nlohmann/json`
-
[**xmake**](https://json.nlohmann.me/integration/package_managers/#xmake) `nlohmann_json`
该库是许多包管理器的一部分。请参阅[**文档**](https://json.nlohmann.me/integration/package_managers/)以获取详细的描述和示例。
### Pkg-config
如果你使用的是普通的 Makefiles,你可以使用 `pkg-config` 生成指向库安装位置的包含标志:
```
pkg-config nlohmann_json --cflags
```
## 许可证
该类根据 [MIT 许可证](https://opensource.org/licenses/MIT) 授权:
版权所有 © 2013-2026 [Niels Lohmann](https://nlohmann.me)
特此免费授予任何获得本软件副本和相关文档文件(“软件”)的人不受限制地处置该软件的权利,包括不受限制地使用、复制、修改、合并、发布、分发、再许可和/或出售该软件副本的权利,以及再授权被配发了本软件的人如上的权利,须在下列条件下:
上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。
本软件按“原样”提供,不提供任何形式的担保,无论是明示或暗示的担保,包括但不限于适销性、特定用途适用性和非侵权性的担保。在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是在合同诉讼、侵权行为还是其他方面,由本软件或本软件的使用或其他交易引起、由此产生或与之相关。
- 该类包含来自 Bjoern Hoehrmann 的 UTF-8 解码器,该解码器根据 [MIT 许可证](https://opensource.org/licenses/MIT) 授权(见上文)。版权所有 © 2008-2009 [Björn Hoehrmann](https://bjoern.hoehrmann.de/)
- 该类包含来自 Florian Loitsch 的 Grisu2 算法的略微修改版本,该算法根据 [MIT 许可证](https://opensource.org/licenses/MIT) 授权(见上文)。版权所有 © 2009 [Florian Loitsch](https://florian.loitsch.com/)
- 该类包含来自 Evan Nemerson 的 [Hedley](https://nemequ.github.io/hedley/) 副本,该副本根据 [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/) 授权。
- 该类包含 [Google Abseil](https://github.com/abseil/abseil-cpp) 的部分内容,该部分根据 [Apache 2.0 许可证](https://opensource.org/licenses/Apache-2.0) 授权。
该库符合 [**REUSE 规范**](https://reuse.software) 版本 3.3:
- 每个源文件都包含 SPDX 版权页眉。
- 存储库中使用的所有许可证的全文可以在 `LICENSES` 文件夹中找到。
- 文件 `.reuse/dep5` 包含所有文件的版权和许可证概述。
- 运行 `pipx run reuse lint` 以验证项目的 REUSE 合规性,运行 `pipx run reuse spdx` 以生成 SPDX SBOM。
## 联系方式
如果你库有疑问,我想邀请你 [在 GitHub 上开启一个 issue](https://github.com/nlohmann/json/issues/new/choose)。请尽可能详细地描述你的请求、问题或疑问,并注明你正在使用的库版本以及编译器和操作系统版本。在 GitHub 上开启 issue 允许该库的其他用户和贡献者进行协作。例如,我对 MSVC 的经验很少,这方面的大多数问题都是由不断增长的社区解决的。如果你查看[已关闭的 issue](https://github.com/nlohmann/json/issues?q=is%3Aissue+is%3Aclosed),你会发现我们在大多数情况下反应相当及时。
只有当你的请求包含机密信息时,请[给我发送电子邮件](mailto:mail@nlohmann.me)。对于加密消息,请使用[此密钥](https://keybase.io/nlohmann/pgp_keys.asc)。
## 安全性
[Niels Lohmann 的提交](https://github.com/nlohmann/json/commits)和[发布版](https://github.com/nlohmann/json/releases)均使用此 [PGP 密钥](https://keybase.io/nlohmann/pgp_keys.asc?fingerprint=797167ae41c0a6d9232e48457f3cea63ae251b69)签名。
## 致谢
我深深感谢以下人员的帮助。
1. [Teemperor](https://github.com/Teemperor) 实现了 CMake 支持和 lcov 集成,实现了字符串解析器中的转义和 Unicode 处理,并修复了 JSON 序列化。
2. [elliotgoodrich](https://github.com/elliotgoodrich) 修复了迭代器类中的双重删除问题。
3. [kirkshoop](https://github.com/kirkshoop) 使类的迭代器可与其他库组合。
4. [wancw](https://github.com/wanwc) 修复了一个阻碍类使用 Clang 编译的 bug。
5. Tomas Åblad 在迭代器实现中发现了一个 bug。
6. [Joshua C. Randall](https://github.com/jrandall) 修复了浮点序列化中的一个 bug。
7. [Aaron Burghardt](https://github.com/aburgh) 实现了增量解析流的代码。此外,他通过允许定义过滤器函数在解析时丢弃不需要的元素,极大地改进了解析器类。
8. [Daniel Kopeček](https://github.com/dkopecek) 修复了使用 GCC 5.0 编译时的一个 bug。
9. [Florian Weber](https://github.com/Florianjw) 修复了比较运算符中的一个 bug 并提高了其性能。
10. [Eric Cornelius](https://github.com/EricMCornelius) 指出了处理 NaN 和无穷大值时的一个 bug。他还提高了字符串转义的性能。
11. [易思龙](https://github.com/likebeta) 实现了从匿名枚举的转换。
12. [kepkin](https://github.com/kepkin) 耐心地推动了对 Microsoft Visual Studio 的支持。
13. [gregmarr](https://github.com/gregmarr) 简化了反向迭代器的实现,并提供了许多提示和改进。特别是,他推动了用户定义类型的实现。
14. [Caio Luppi](https://github.com/caiovlp) 修复了 Unicode 处理中的一个 bug。
15. [dariomt](https://github.com/dariomt) 修复了示例中的一些拼写错误。
16. [Daniel Frey](https://github.com/d-frey) 清理了一些指针并实现了异常安全的内存分配。
17. [Colin Hirsch](https://github.com/ColinH) 处理了一个小的命名空间问题。
18. [Huu Nguyen](https://github.com/whoshuu) 更正了文档中的变量名。
19. [Silverweed](https://github.com/silverweed) 重载了 `parse()` 以接受右值引用。
20. [dariomt](https://github.com/dariomt) 修复了 MSVC 类型支持中的一个细微差别,并实现了 `get_ref()` 函数以获取对存储值的引用。
21. [ZahlGraf](https://github.com/ZahlGraf) 添加了一个允许使用 Android NDK 进行编译的变通方法。
22. [whackashoe](https://github.com/whackashoe) 替换了一个被 Visual Studio 标记为不安全的函数。
23. [406345](https://github.com/406345) 修复了两个小警告。
24. [Glen Fernandes](https://github.com/glenfe) 指出了 `has_mapped_type` 函数中潜在的移植性问题。
25. [Corbin Hughes](https://github.com/nibroc) 修复了贡献指南中的一些拼写错误。
26. [twelsby](https://github.com/twelsby) 修复了数组下标运算符、一个导致 MSVC 构建失败的问题以及浮点解析/转储。他还添加了对无符号整数的支持,并实现了更好的解析数字往返支持。
27. [Volker Diels-Grabsch](https://github.com/vog) 修复了 README 文件中的一个链接。
28. [msm-](https://github.com/msm-) 添加了对 American Fuzzy Lop 的支持。
29. [Annihil](https://github.com/Annihil) 修复了 README 文件中的一个示例。
30. [Themercee](https://github.com/Themercee) 指出了 README 文件中错误的 URL。
31. [Lv Zheng](https://github.com/lv-zheng) 修复了 `int64_t` 和 `uint64_t` 的命名空间问题。
32. [abc100m](https://github.com/abc100m) 分析了 GCC 4.8 的问题并提出了[部分解决方案](https://github.com/nlohmann/json/pull/212)。
33. [zewt](https://github.com/zewt) 在 README 文件中添加了关于 Android 的有用说明。
34. [Róbert Márki](https://github.com/robertmrk) 添加了一个修复以使用移动迭代器并通过 CMake 改进了集成。
35. [Chris Kitching](https://github.com/ChrisKitching) 清理了 CMake 文件。
36. [Tom Needham](https://github.com/06needhamt) 修复了 MSVC 2015 的一个微妙 bug,该 bug 也是由 [Michael K.](https://github.com/Epidal) 提出的。
37. [Mário Feroldi](https://github.com/thelostt) 修复了一个小拼写错误。
38. [duncanwerner](https://github.com/duncanwerner) 发现了 2.0.0 版本中一个非常令人尴尬的性能回归。
39. [Damien](https://github.com/dtoma) 修复了最后一个转换警告之一。
40. [Thomas Braun](https://github.com/t-b) 修复了测试用例中的警告并调整了 CI 中的 MSVC 调用。
41. [Théo DELRIEU](https://github.com/theodelrieu) 耐心且建设性地监督了通往[迭代器范围解析](https://github.com/nlohmann/json/issues/290)的漫长道路。他还实现了用户定义类型序列化/反序列化背后的魔法,并将单个头文件拆分为更小的块。
42. [Stefan](https://github.com/5tefan) 修复了文档中的一个小问题。
43. [Vasil Dimov](https://github.com/vasild) 修复了关于从 `std::multiset` 转换的文档。
44. [ChristophJud](https://github.com/ChristophJud) 改进了 CMake 文件以简化项目包含。
45. [Vladimir Petrigo](https://github.com/vpetrigo) 使 SFINAE hack 更具可读性,并将 Visual Studio 17 添加到构建矩阵中。
46. [Denis Andrejew](https://github.com/seeekr) 修复了 README 文件中的语法问题。
47. [Pierre-Antoine Lacaze](https://github.com/palacaze) 在 `dump()` 函数中发现了一个微妙的 bug。
48. [TurpentineDistillery](https://github.com/TurpentineDistillery) 指向 [`std::locale::classic()`](https://en.cppreference.com/w/cpp/locale/locale/classic) 以避免过多的 locale 切换,在解析器中发现了一些不错的性能改进,改进了基准测试代码,并实现了与 locale 无关的数字解析和打印。
49. [cgzones](https://github.com/cgzones) 有一个如何修复 Coverity 扫描的想法。
50. [Jared Grubb](https://github.com/jaredgrubb) 消除了一个恼人的文档警告。
51. [Yixin Zhang](https://github.com/qwename) 修复了整数溢出检查。
52. [Bosswestfalen](https://github.com/Bosswestfalen) 将两个迭代器类合并为一个更小的类。
53. [Daniel599](https://github.com/Daniel599) 帮助让 Travis 使用 Clang 的 sanitizers 执行测试。
54. [Jonathan Lee](https://github.com/vjon) 修复了 README 文件中的一个示例。
55. [gnzlbg](https://github.com/gnzlbg) 支持用户定义类型的实现。
56. [Alexej Harm](https://github.com/qis) 帮助让用户定义类型在 Visual Studio 中工作。
57. [Jared Grubb](https://github.com/jaredgrubb) 支持用户定义类型的实现。
58. [EnricoBilla](https://github.com/EnricoBilla) 指出了示例中的一个拼写错误。
59. [Martin Hořeňovský](https://github.com/horenmar) 找到了一种将测试套件的编译时间加快 2 倍的方法。
60. [ukhegg](https://github.com/ukhegg) 为示例部分提出了一项改进建议。
61. [rswanson-ihi](https://github.com/rswanson-ihi) 指出了 README 中的一个拼写错误。
62. [Mihai Stan](https://github.com/stanmihai4) 修复了与 `nullptr` 比较的一个 bug。
63. [Tushar Maheshwari](https://github.com/tusharpm) 添加了 [cotire](https://github.com/sakra/cotire) 支持以加快编译速度。
64. [TedLyngmo](https://github.com/TedLyngmo) 指出了 README 中的一个拼写错误,删除了不必要的位运算,并修复了一些 `-Weffc++` 警告。
65. [Krzysztof Woś](https://github.com/krzysztofwos) 使异常更加可见。
66. [ftillier](https://github.com/ftillier) 修复了编译器警告。
67. [tinloaf](https://github.com/tinloaf) 确保所有推入的警告都被正确弹出。
68. [Fytch](https://github.com/Fytch) 在文档中发现了一个 bug。
69. [Jay Sistar](https://github.com/Type1J) 实现了 Meson 构建描述。
70. [Henry Lee](https://github.com/HenryRLee) 修复了 ICC 中的警告并改进了迭代器实现。
71. [Vincent Thiery](https://github.com/vthiery) 维护 Conan 包管理器的包。
72. [Steffen](https://github.com/koemeet) 修复了 MSVC 和 `std::min` 的潜在问题。
73. [Mike Tzou](https://github.com/Chocobo1) 修复了一些拼写错误。
74. [amrcode](https://github.com/amrcode) 指出了关于浮点比较的误导性文档。
75. [Oleg Endo](https://github.com/olegendo) 通过用 `` 替换 `` 来减少内存消耗。
76. [dan-42](https://github.com/dan-42) 清理了 CMake 文件以简化库的包含/重用。
77. [Nikita Ofitserov](https://github.com/himikof) 允许从初始化列表移动值。
78. [Greg Hurrell](https://github.com/wincent) 修复了一个拼写错误。
79. [Dmitry Kukovinets](https://github.com/DmitryKuk) 修复了一个拼写错误。
80. [kbthomp1](https://github.com/kbthomp1) 修复了与 Intel OSX 编译器相关的问题。
81. [Markus Werle](https://github.com/daixtrose) 修复了一个拼写错误。
82. [WebProdPP](https://github.com/WebProdPP) 修复了前置条件检查中的一个微妙错误。
83. [Alex](https://github.com/leha-bot) 指出了代码示例中的一个错误。
84. [Tom de Geus](https://github.com/tdegeus) 报告了 ICC 的一些警告并帮助修复了它们。
85. [Perry Kundert](https://github.com/pjkundert) 简化了从输入流读取。
86. [Sonu Lohani](https://github.com/sonulohani) 修复了一个小的编译错误。
87. [Jamie Seward](https://github.com/jseward) 修复了所有 MSVC 警告。
88. [Nate Vargas](https://github.com/eld00d) 添加了一个 Doxygen 标签文件。
89. [pvleuven](https://github.com/pvleuven) 帮助修复了 ICC 中的警告。
90. [Pavel](https://github.com/crea7or) 帮助修复了 MSVC 中的一些警告。
91. [Jamie Seward](https://github.com/jseward) 避免了 `find()` 和 `count()` 中不必要的字符串复制。
92. [Mitja](https://github.com/Itja) 修复了一些拼写错误。
93. [Jorrit Wronski](https://github.com/jowr) 更新了 Hunter 包链接。
94. [Matthias Möller](https://github.com/TinyTinni) 为 MSVC 调试视图添加了 `.natvis`。
95. [bogemic](https://github.com/bogemic) 修复了一些 C++17 弃用警告。
96. [Eren Okka](https://github.com/erengy) 修复了一些 MSVC 警告。
97. [abolzhttps://github.com/abolz) 集成了 Grisu2 算法以进行正确的浮点格式化,允许更多的往返检查成功。
98. [Vadim Evard](https://github.com/Pipeliner) 修复了 README 中的 Markdown 问题。
99. [zerodefect](https://github.com/zerodefect) 修复了编译器警告。
100. [Kert](https://github.com/kaidokert) 允许在序列化中模板化字符串类型,并添加了覆盖异常行为的可能性。
101. [mark-99](https://github.com/mark-99) 帮助修复了 ICC 错误。
102. [Patrik Huber](https://github.com/patrikhuber) 修复了 README 文件中的链接。
103. [johnfb](https://github.com/johnfb) 在 CBOR 不定长度字符串的实现中发现了一个 bug。
104. [Paul Fultz II](https://github.com/pfultz2) 添加了关于 cget 包管理器的说明。
105. [Wilson Lin](https://github.com/wla80) 使 README 的集成部分更加简洁。
106. [RalfBielig](https://github.com/ralfbielig) 检测并修复了解析器回调中的内存泄漏。
107. [agrianius](https://github.com/agrianius) 允许将 JSON dump 到替代字符串类型。
108. [Kevin Tonon](https://github.com/ktonon) 改进了 CMake 中的 C++11 编译器检查。
109. [Axel Huebl](https://github.com/ax3l) 简化了 CMake 检查并添加了对 [Spack 包管理器](https://spack.io)的支持。
110. [Carlos O'Ryan](https://github.com/coryan) 修复了一个拼写错误。
111. [James Upjohn](https://github.com/jammehcow) 修复了编译器部分中的版本号。
112. [Chuck Atkins](https://github.com/chuckatkins) 调整了 CMake 文件以符合 CMake 打包指南,并提供了 CMake 集成的文档。
113. [Jan Schöppach](https://github.com/dns13) 修复了一个拼写错误。
114. [martin-mfg](https://github.com/martin-mfg) 修复了一个拼写错误。
115. [Matthias Möller](https://github.com/TinyTinni) 删除了对 `std::stringstream` 的依赖。
116. [agrianius](https://github.com/agrianius) 添加了使用替代字符串实现的代码。
117. [Daniel599](https://github.com/Daniel599) 允许在 `items()` 函数中使用更多算法。
118. [Julius Rakow](https://github.com/jrakow) 修复了 Meson 包含目录并修复了指向 [cppreference.com](https://cppreference.com) 的链接。
119. [Sonu Lohani](https://github.com/sonulohani) 修复了在调试模式下使用 MSVC 2015 的编译。
120. [grembo](https://github.com/grembo) 修复了测试套件并重新启用了几个测试用例。
121. [Hyeon Kim](https://github.com/simnalamburt) 引入了宏 `JSON_INTERNAL_CATCH` 来控制库内部的异常处理。
122. [thyu](https://github.com/thyu) 修复了编译器警告。
123. [David Guthrie](https://github.com/LEgregius) 修复了 Clang 3.4.2 的一个微妙编译错误。
124. [Dennis Fischer](https://github.com/dennisfischer) 允许在不安装库的情况下调用 `find_package`。
125. [Hyeon Kim](https://github.com/simnalamburt) 修复了双重宏定义的问题。
126. [Ben Berman](https://github.com/rivertam) 使一些错误消息更易于理解。
127. [zakalibit](https://github.com/zakalibit) 修复了 Intel C++ 编译器的编译问题。
128. [mandreyel](https://github.com/mandreyel) 修复了一个编译问题。
129. [Kostiantyn Ponomarenko](https://github.com/koponomarenko) 在 Meson 构建文件中添加了版本和许可证信息。
130. [Henry Schreiner](https://github.com/henryiii) 添加了对 GCC 4.8 的支持。
131. [knilch](https://github.com/knilch0r) 确保测试套件在错误的目录中运行时不会停止。
132. [Antonio Borondo](https://github.com/antonioborondo) 修复了 MSVC 2017 警告。
133. [Dan Gendreau](https://github.com/dgendreau) 实现了 `NLOHMANN_JSON_SERIALIZE_ENUM` 宏以快速定义枚举/JSON 映射。
134. [efp](https://github.com/efp) 在解析错误中添加了行和列信息。
135. [julian-becker](https://github.com/julian-becker) 添加了 BSON 支持。
136. [Pratik Chowdhury](https://github.com/pratikpc) 添加了对结构化绑定的支持。
137. [David Avedissian](https://github.com/davedissian) 添加了对 Clang 5.0.1(PS4 版本)的支持。
138. [Jonathan Dumaresq](https://github.com/dumarjo) 实现了一个输入适配器以从 `FILE*` 读取。
139. [kjpus](https://github.com/kjpus) 修复了文档中的链接。
140. [Manvendra Singh](https://github.com/manu-chroma) 修复了文档中的拼写错误。
141. [ziggurat29](https://github.com/ziggurat29) 修复了 MSVC 警告。
142. [Sylvain Corlay](https://github.com/SylvainCorlay) 添加了代码以避免 MSVC 的问题。
143. [mefyl](https://github.com/mefyl) 修复了从输入流解析 JSON 时的 bug。
144. [Millian Poquet](https://github.com/mpoquet) 允许通过 Meson 安装库。
145. [Michael Behrns-Miller](https://github.com/moodboom) 发现了一个缺少命名空间的问题。
146. [Nasztanovics Ferenc](https://github.com/naszta) 修复了 libc 2.12 的编译问题。
147. [Andreas Schwab](https://github.com/andreas-schwab) 修复了字节序转换。
148. [Mark-Dunning](https://github.com/Mark-Dunning) 修复了 MSVC 中的警告。
149. [Gareth Sylvester-Bradley](https://github.com/garethsb-sony) 为 JSON Pointers 添加了 `operator/`。
150. [John-Mark](https://github.com/johnmarkwayve) 指出缺少头文件。
151. [Vitaly Zaitsev](https://github.com/xvitaly) 修复了 GCC 9.0 的编译。
152. [Laurent Stacul](https://github.com/stac47) 修复了 GCC 9.0 的编译。
153. [Ivor Wanders](https://github.com/iwanders) 帮助将 CMake 要求降低到版本 3.1。
154. [njlr](https://github.com/njlr) 更新了 Buckaroo 说明。
155. [Lion](https://github.com/lieff) 修复了 CentOS 上 GCC 7 的编译问题。
156. [Isaac Nickaein](https://github.com/nickaein) 提高了整数序列化性能并实现了 `contains()` 函数。
157. [past-due](https://github.com/past-due) 抑制了一个无法修复的警告。
158. [Elvis Oric](https://github.com/elvisoric) 改进了 Meson 支持。
159. [Matěj Plch](https://github.com/Afforix) 修复了 README 中的一个示例。
160. [Mark Beckwith](https://github.com/wythe) 修复了一个拼写错误。
161. [scinart](https://github.com/scinart) 修复了序列化器中的 bug。
162. [Patrick Boettcher](https://github.com/pboettch) 为 JSON Pointers 实现了 `push_back()` 和 `pop_back()`。
163. [Bruno Oliveira](https://github.com/nicoddemus) 添加了对 Conda 的支持。
164. [Michele Caini](https://github.com/skypjack) 修复了 README 中的链接。
165. [Hani](https://github.com/hnkb) 记录了如何使用 NuGet 安装库。
166. [Mark Beckwith](https://github.com/wythe) 修复了一个拼写错误。
167. [yann-morin-1998](https://github.com/yann-morin-1998) 帮助将 CMake 要求降低到版本 3.1。
168. [Konstantin Podsvirov](https://github.com/podsvirov) 维护 MSYS2 软件发行版的包。
169. [remyabel](https://github.com/remyabel) 在 CMake 文件中添加了 GNUInstallDirs。
170. [Taylor Howard](https://github.com/taylorhoward92) 修复了一个单元测试。
171. [Gabe Ron](https://github.com/Macr0Nerd) 实现了 `to_string` 方法。
172. [Watal M. Iwasaki](https://github.com/heavywatal) 修复了 Clang 警告。
173. [Viktor Kirilov](https://github.com/onqtam) 将单元测试从 [Catch](https://github.com/philsquared/Catch) 切换到 [doctest](https://github.com/onqtam/doctest)
174. [Juncheng E](https://github.com/ejcjason) 修复了一个拼写错误。
175. [tete17](https://github.com/tete17) 修复了 `contains` 函数中的 bug。
176. [Xav83](https://github.com/Xav83) 修复了一些 cppcheck 警告。
177. [0xflotus](https://github.com/0xflotus) 修复了一些拼写错误。
178. [Christian Deneke](https://github.com/chris0x44) 添加了 `json_pointer::back` 的 const 版本。
179. [Julien Hamaide](https://github.com/crazyjul) 使 `items()` 函数适用于自定义字符串类型。
180. [Evan Nemerson](https://github.com/nemequ) 修复了 Hedley 中的 bug 并相应地更新了该库。
181. [Florian Pigorsch](https://github.com/flopp) 修复了很多拼写错误。
182. [Camille Bégué](https://github.com/cbegue) 修复了从 `std::pair` 和 `std::tuple` 转换到 `json` 的问题。
183. [Anthony VH](https://github.com/AnthonyVH) 修复了枚举反序列化中的编译错误。
184. [Yuriy Vountesmery](https://github.com/ua-code-dragon) 指出了预处理器检查中的一个微妙 bug。
185. [Chen](https://github.com/dota17) 修复了库中的许多问题。
186. [Antony Kellermann](https://github.com/aokellermann) 为 GCC 10.1 添加了一个 CI 步骤。
187. [Alex](https://github.com/gistrec) 修复了 MSVC 警告。
188. [Rainer](https://github.com/rvjr) 提出了 CBOR 浮点序列化的改进建议。
189. [Francois Chabot](https://github.com/FrancoisChabot) 在输入适配器中进行了性能改进。
190. [Arthur Sonzogni](https://github.com/ArthurSonzogni) 记录了如何通过 `FetchContent` 包含该库。
191. [Rimas Misevičius](https://github.com/rmisev) 修复了一个错误消息。
192. [Alexander Myasnikov](https://github.com/alexandermyasnikov) 修复了一些示例和 README 中的链接。
193. [Hubert Chathi](https://github.com/uhoreg) 使 CMake 的版本配置文件与体系结构无关。
194. [OmnipotentEntity](https://github.com/OmnipotentEntity) 实现了 CBOR、MessagePack、BSON 和 UBJSON 的二进制值。
195. [ArtemSarmini](https://github.com/ArtemSarmini) 修复了 GCC 10 的编译问题并修复了泄漏。
196. [Evgenii Sopov](https://github.com/sea-kg) 将库集成到 wsjcpp 包管理器中。
197. [Sergey Linev](https://github.com/linev) 修复了编译器警告。
198. [Miguel Magalhães](https://github.com/magamig) 修复了版权中的年份。
199. [Gareth Sylvester-Bradley](https://github.com/garethsb-sony) 修复了 MSVC 的编译问题。
200. [Alexander “weej” Jones](https://github.com/alex-weej) 修复了 README 中的一个示例。
201. [Antoine Cœur](https://github.com/Coeur) 修复了文档中的一些拼写错误。
202. [jothepro](https://github.com/jothepro) 更新了指向 Hunter 包的链接。
203. [Dave Lee](https://github.com/kastiglione) 修复了 README 中的链接。
204. [Joël Lamotte](https://github.com/Klaim) 添加了使用 Build2 包管理器的说明。
205. [Paul Jurczak](https://github.com/pauljurczak) 修复了 README 中的一个示例。
206. [Sonu Lohani](https://github.com/sonulohani) 修复了一个警告。
207. [Carlos Gomes Martinho](#customers) 更新了 Conan 包源。
208. [Konstantin Podsvirov](https://github.com/podsvirov) 修复了 MSYS2 包文档。
209. [Tridacnid](https://github.com/Tridacnid) 改进了 CMake 测试。
210. [Michael](https://github.com/MBalszun) 修复了 MSVC 警告。
211. [Quentin Barbarat](https://github.com/quentin-dev) 修复了文档中的一个示例。
212. [XyFreak](https://github.com/XyFreak) 修复了编译器警告。
213. [TotalCaesar659](https://github.com/TotalCaesar659) 修复了 README 中的链接。
214. [Tanuj Garg](https://github.com/tanuj208) 改进了 UBSAN 输入的模糊器覆盖率。
215. [AODQ](https://github.com/AODQ) 修复了编译器警告。
216. [jwittbrodt](https://github.com/jwittbrodt) 使 `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE` 内联。
217. [pfeatherstone](https://github.com/pfeatherstone) 改进了 `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`/`NLOHMANN_DEFINE_TYPE_INTRUSIVE` 宏的参数上限。
218. [Jan Procházka](https://github.com/jprochazk) 修复了 CBOR 解析器中二进制和字符串值的 bug。
219. [T0b1-iOS](https://github.com/T0b1-iOS) 修复了新哈希实现中的 bug。
220. [Matthew Bauer](https://github.com/matthewbauer) 调整了 CBOR 编写器以为二进制子类型创建标签。
221. [gatopeich](https://github.com/gatopeich) 为 `nlohmann::ordered_json` 实现了一个有序映射容器。
222. [Érico Nogueira Rolim](https://github.com/ericonr) 添加了对 pkg-config 的支持。
223. [KonanM](https://github.com/KonanM) 提议了 `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`/`NLOHMANN_DEFINE_TYPE_INTRUSIVE` 宏的实现。
224. [Guillaume Racicot](https://github.com/gracicot) 实现了 `string_view` 支持并允许 C++20 支持。
225. [Alex Reinking](https://github.com/alexreinking) 改进了 `FetchContent` 的 CMake 支持。
226. [Hannes Domani](https://github.com/ssbssa) 提供了一个 GDB 漂亮打印机。
227. Lars Wirzenius 审查了 README 文件。
228. [Jun Jie](https://github.com/ongjunjie) 修复了 CMake 脚本中的编译器路径。
229. [Ronak Buch](https://github.com/rbuch) 修复了文档中的拼写错误。
230. [Alexander Karzhenkov](https://github.com/karzhenkov) 修复了移动构造函数和 Travis 构建。
231. [Leonardo Lima](https://github.com/leozz37) 添加了 CPM.Cmake 支持。
232. [Joseph Blackman](https://github.com/jbzdarkid) 修复了一个警告。
233. [Yaroslav](https://github.com/YarikTH) 更新了 doctest 并实现了单元测试。
234. [Martin Stump](https://github.com/globberwops) 修复了 CMake 文件中的 bug。
235. [Jaakko Moisio](https://github.com/jasujm) 修复了输入适配器中的 bug。
236. [bl-ue](https://github.com/bl-ue) 修复了 README 文件中的一些 Markdown 问题。
237. [William A. Wieselquist](https://github.com/wawiesel) 修复了 README 中的一个示例。
238. [abbaswasim](https://github.com/abbaswasim) 修复了 README 中的一个示例。
239. [Remy Jette](https://github.com/remyjette) 修复了一个警告。
240. [Fraser](https://github.com/frasermarlow) 修复了文档。
241. [Ben Beasley](https://github.com/musicinmybrain) 更新了 doctest。
242. [Doron Behar](https://github.com/doronbehar) 修复了 pkg-config.pc。
243. [raduteo](https://github.com/raduteo) 修复了一个警告。
244. [David Pfahler](https://github.com/theShmoo) 添加了在没有 I/O 支持的情况下编译库的可能性。
245. [Morten Fyhn Amundsen](https://github.com/mortenfyhn) 修复了一个拼写错误。
246. [jpl-mac](https://github.com/jpl-mac) 允许在 CMake 中将库视为系统头文件。
247. [Jason Dsouza](https://github.com/jasmcaus) 修复了 CMake 文件的缩进。
248. [offa](https://github.com/offa) 在文档中添加了指向 Conan Center 的链接。
249. [TotalCaesar659](https://github.com/TotalCaesar659) 更新了文档中的链接以使用 HTTPS。
250. [Rafail Giavrimis](https://github.com/grafail)
367. [Dylan Baker](https://github.com/dcbaker) 生成了一个遵循 pkg-config 约定的 pkg-config 文件。
368. [Tianyi Chen](https://github.com/TianyiChen) 优化了二进制 `get_number` 实现。
369. [peng-wang-cn](https://github.com/peng-wang-cn) 添加了对多维数组的类型转换支持。
370. [Einars Netlis-Galejs](https://github.com/EinarsNG) 为 `NLOHMANN_DEFINE_DERIVED_TYPE_*` 宏添加了 `ONLY_SERIALIZE`。
371. [Marcel](https://github.com/mering) 移除了 `alwayslink=True` Bazel 标志。
372. [Harinath Nampally](https://github.com/hnampally) 为异常添加了诊断位置。
373. [Nissim Armand Ben Danan](https://github.com/NissimBendanan) 修复了 `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT` 在空 JSON 实例下的问题。
374. [Michael Valladolid](https://github.com/codenut) 添加了对 BSON uint64 序列化/反序列化的支持。
375. [Nikhil](https://github.com/nikhilreddydev) 更新了文档。
376. [Nebojša Cvetković](https://github.com/nebkat) 添加了对 BJDATA 优化二进制数组类型的支持。
377. [Sushrut Shringarputale](https://github.com/sushshring) 添加了对诊断位置的支持。
378. [kimci86](https://github.com/kimci86) 将 `NLOHMANN_DEFINE_TYPE` 宏模板化以支持 `ordered_json`。
379. [Richard Topchii](https://github.com/richardtop) 在 Swift Package Manager 中添加了对 VisionOS 的支持。
380. [Robert Chisholm](https://github.com/Robadob) 修复了一个拼写错误。
381. [zjyhjqs](https://github.com/zjyhjqs) 添加了 CPack 支持。
382. [bitFiedler](https://github.com/bitFiedler) 使 GDB 漂亮打印机兼容 Python 3.8。
383. [Gianfranco Costamagna](https://github.com/LocutusOfBorg) 修复了一个编译器警告。
384. [risa2000](https://github.com/risa2000) 使 `std::filesystem::path` 与 UTF-8 编码字符串之间的转换变为显式。
非常感谢您的帮助!如果我遗漏了某人,请[告诉我](mailto:mail@nlohmann.me)。
## 使用的第三方工具
该库本身由一个 MIT 许可证授权的头文件组成。然而,它的构建、测试、文档编写等使用了大量的第三方工具和服务。非常感谢!
- [**amalgamate.py - Amalgamate C source and header files**](https://github.com/edlund/amalgamate) 用于创建单体头文件
- [**American fuzzy lop**](https://lcamtuf.coredump.cx/afl/) 用于模糊测试
- [**AppVeyor**](https://www.appveyor.com) 用于 Windows 上的[持续集成](https://ci.appveyor.com/project/nlohmann/json)
- [**Artistic Style**](http://astyle.sourceforge.net) 用于自动源代码缩进
- [**Clang**](https://clang.llvm.org) 用于使用代码消毒器进行编译
- [**CMake**](https://cmake.org) 用于构建自动化
- [**Codacy**](https://www.codacy.com) 用于进一步的[代码分析](https://app.codacy.com/gh/nlohmann/json/dashboard)
- [**Coveralls**](https://coveralls.io) 用于测量[代码覆盖率](https://coveralls.io/github/nlohmann/json)
- [**Coverity Scan**](https://scan.coverity.com) 用于[静态分析](https://scan.coverity.com/projects/nlohmann-json)
- [**cppcheck**](http://cppcheck.sourceforge.net) 用于静态分析
- [**doctest**](https://github.com/onqtam/doctest) 用于单元测试
- [**GitHub Changelog Generator**](https://github.com/skywinder/github-changelog-generator) 用于生成[更新日志](https://github.com/nlohmann/json/blob/develop/ChangeLog.md)
- [**Google Benchmark**](https://github.com/google/benchmark) 用于实现性能测试
- [**Hedley**](https://nemequ.github.io/hedley/) 用于避免重复造轮子实现多个编译器无关的特性宏
- [**lcov**](https://github.com/linux-test-project/lcov) 用于处理覆盖率信息并创建 HTML 视图
- [**libFuzzer**](https://llvm.org/docs/LibFuzzer.html) 用于为 OSS-Fuzz 实现模糊测试
- [**Material for MkDocs**](https://squidfunk.github.io/mkdocs-material/) 用于文档站点的样式
- [**MkDocs**](https://www.mkdocs.org) 用于文档站点
- [**OSS-Fuzz**](https://github.com/google/oss-fuzz) 用于对库进行持续的模糊测试([项目仓库](https://github.com/google/oss-fuzz/tree/master/projects/json))
- [**Probot**](https://probot.github.io) 用于自动化维护者的任务,例如关闭过时的 issue、请求缺失的信息或检测有毒评论。
- [**Valgrind**](https://valgrind.org) 用于检查正确的内存管理
## 说明
### 字符编码
该库支持 **Unicode 输入**,规则如下:
- 仅支持 **UTF-8** 编码的输入,这是根据 [RFC 8259](https://tools.ietf.org/html/rfc8259.html#section-8.1) 规定的 JSON 默认编码。
- 可以解析 `std::u16string` 和 `std::u32string`,分别假设为 UTF-16 和 UTF-32 编码。从文件或其他输入容器读取时不支持这些编码。
- **不**支持其他编码(如 Latin-1 或 ISO 8859-1),这将导致解析或序列化错误。
- 库不会替换 [Unicode 非字符](https://www.unicode.org/faq/private_use.html#nonchar1)。
- 无效的代理项(例如,不完整的对,如 `\uDEAD`)将导致解析错误。
- 存储在库中的字符串是 UTF-8 编码的。当使用默认字符串类型(`std::string`)时,请注意其长度/大小函数返回的是存储的字节数,而不是字符数或字形数。
- 如果您在库中存储了不同编码的字符串,调用 [`dump()`](https://json.nlohmann.me/api/basic_json/dump/) 可能会抛出异常,除非使用 `json::error_handler_t::replace` 或 `json::error_handler_t::ignore` 作为错误处理器。
- 要存储宽字符串(例如 `std::wstring`),您需要先将其转换为 UTF-8 编码的 `std::string`,参见[示例](https://json.nlohmann.me/home/faq/#wide-string-handling)。
### JSON 中的注释
该库默认不支持注释。这样做有三个原因:
1. 注释不是 [JSON 规范](https://tools.ietf.org/html/rfc8259)的一部分。您可能会争辩说 `//` 或 `/* */` 在 JavaScript 中是允许的,但 JSON 不是 JavaScript。
2. 这不是疏忽:Douglas Crockford 在 2012 年 5 月[对此写道](https://plus.google.com/118095276221607585885/posts/RK8qyGVaGSr):
3. 如果某些库添加注释支持而其他库不支持,这对互操作性是危险的。请参阅关于此问题的 [The Harmful Consequences of the Robustness Principle](https://tools.ietf.org/html/draft-iab-protocol-maintenance-01)。
但是,您可以在 `parse` 函数中将参数 `ignore_comments` 设置为 true,以忽略 `//` 或 `/* */` 注释。注释随后将被视为空白符。
### 尾随逗号
JSON 规范不允许在数组和对象中使用尾随逗号,因此该库默认将它们视为解析错误。
与注释类似,您可以在 `parse` 函数中将参数 `ignore_trailing_commas` 设置为 true,以忽略数组和对象中的尾随逗号。请注意,单个逗号作为数组或对象的唯一内容(`[,]` 或 `{,}`)是不允许的,并且多个尾随逗号(`[1,,]`)也是不允许的。
该库在序列化 JSON 数据时不会添加尾随逗号。
更多信息,请参阅 [JSON With Commas and Comments (JWCC)](https://nigeltao.github.io/blog/2021/json-with-commas-comments.html)。
### 对象键的顺序
默认情况下,库不保留 **对象元素的插入顺序**。这是符合标准的,因为 [JSON 标准](https://tools.ietf.org/html/rfc8259.html)将对象定义为“零个或多个名称/值对的无序集合”。
如果您确实希望保留插入顺序,可以尝试使用 [`nlohmann::ordered_json`](https://github.com/nlohmann/json/issues/2179) 类型。或者,您可以使用更复杂的有序映射,如 [`tsl::ordered_map`](https://github.com/Tessil/ordered-map)([集成](https://github.com/nlohmann/json/issues/546#issuecomment-304447518))或 [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map)([集成](https://github.com/nlohmann/json/issues/485#issuecomment-333652309))。
有关更多信息,请参阅 [**关于对象顺序的文档**](https://json.nlohmann.me/features/object_order/)。
### 内存释放
我们使用 Valgrind 和 Address Sanitizer (ASAN) 进行了检查,确认没有内存泄漏。
如果您发现使用此库的解析程序没有释放内存,请考虑以下情况,这可能与此库无关。
**您的程序是使用 glibc 编译的。** glibc 使用一个可调的阈值来决定是实际将内存归还给系统,还是将其缓存以备后用。如果在您的程序中进行了大量的小块分配,并且这些小块分配不是连续的块且可能低于阈值,那么它们将不会归还给操作系统。
这是一个相关问题 [#1924](https://github.com/nlohmann/json/issues/1924)。
### 其他说明
- 代码包含大量的调试 **断言**,可以通过定义预处理器宏 `NDEBUG` 来关闭,参见 [`assert` 的文档](https://en.cppreference.com/w/cpp/error/assert)。特别是注意 [`operator[]`](https://json.nlohmann.me/api/basic_json/operator%5B%5D/) 为 const 对象实现了 **未检查访问**:如果给定的键不存在,行为是未定义的(想想解引用空指针),如果开启了断言,会导致 [断言失败](https://github.com/nlohmann/json/issues/289)。如果您不确定对象中是否存在某个元素,请使用 [`at()` 函数](https://json.nlohmann.me/api/basic_json/at/)进行已检查访问。此外,您可以定义 `JSON_ASSERT(x)` 来替换对 `assert(x)` 的调用。有关更多信息,请参阅 [**关于运行时断言的文档**](https://json.nlohmann.me/features/assertions/)。
- 由于 [JSON 规范](https://tools.ietf.org/html/rfc8259.html)中未定义确切的数字类型,此库尝试自动选择最合适的 C++ 数字类型。因此,可能会使用 `double` 类型来存储数字,如果在调用代码中未屏蔽浮点异常,在某些罕见情况下可能会导致 [**浮点异常**](https://github.com/nlohmann/json/issues/181)。这些异常不是由库引起的,需要在调用代码中修复,例如在调用库函数之前重新屏蔽异常。
- 代码可以在没有 C++ **运行时类型识别** 功能的情况下编译;也就是说,您可以使用 `-fno-rtti` 编译器标志。
- 库中广泛使用了 **异常**。然而,可以通过使用编译器标志 `-fno-exceptions` 或定义符号 `JSON_NOEXCEPTION` 来关闭它们。在这种情况下,异常将被 `abort()` 调用替换。您还可以通过定义 `JSON_THROW_USER`(覆盖 `throw`)、`JSON_TRY_USER`(覆盖 `try`)和 `JSON_CATCH_USER`(覆盖 `catch`)来进一步控制此行为。请注意,`JSON_THROW_USER` 应该离开当前作用域(例如,通过抛出或中止),因为在它之后继续执行可能会导致未定义的行为。请注意,如果禁用了异常,MSVC 将无法使用异常的解释性 [`what()`](https://en.cppreference.com/w/cpp/error/exception/what) 字符串,参见 [#2824](https://github.com/nlohmann/json/discussions/2824)。有关更多信息,请参阅 [**异常文档**](https://json.nlohmann.me/home/exceptions/)。
## 执行单元测试
要编译并运行测试,您需要执行
```
mkdir build
cd build
cmake .. -DJSON_BuildTests=On
cmake --build .
ctest --output-on-failure
```
请注意,在 `ctest` 阶段,会从[外部仓库](https://github.com/nlohmann/json_test_data)下载几个 JSON 测试文件。如果策略禁止在测试期间下载工件,您可以自行下载文件,并通过 `-DJSON_TestDataDirectory=path` 将测试文件目录传递给 CMake。这样就不需要网络连接。有关更多信息,请参阅 [issue #2189](https://github.com/nlohmann/json/issues/2189)。
如果找不到测试数据,几个测试套件将失败,如下所示:
```
===============================================================================
json/tests/src/make_test_data_available.hpp:21:
TEST CASE: check test suite is downloaded
json/tests/src/make_test_data_available.hpp:23: FATAL ERROR: REQUIRE( utils::check_testsuite_downloaded() ) is NOT correct!
values: REQUIRE( false )
logged: Test data not found in 'json/cmake-build-debug/json_test_data'.
Please execute target 'download_test_data' before running this test suite.
See for more information.
===============================================================================
```
如果您是下载了库而不是通过 Git 检出代码,测试 `cmake_fetch_content_configure` 将失败。请执行 `ctest -LE git_required` 以跳过这些测试。有关更多信息,请参阅 [issue #2189](https://github.com/nlohmann/json/issues/2189)。
有些测试需要网络才能正常执行。它们被标记为 `git_required`。请执行 `ctest -LE git_required` 以跳过这些测试。有关更多信息,请参阅 [issue #4851](https://github.com/nlohmann/json/issues/4851)。
有些测试会更改已安装的文件,从而使整个过程不可复现。请执行 `ctest -LE not_reproducible` 以跳过这些测试。有关更多信息,请参阅 [issue #2324](https://github.com/nlohmann/json/issues/2324)。此外,必须关闭断言以确保可复现的构建(参见 [讨论 4494](https://github.com/nlohmann/json/discussions/4494))。
请注意,您需要调用 `cmake -LE "not_reproducible|git_required"` 来排除这两个标签。有关更多信息,请参阅 [issue #2596]( )。
由于 Intel 编译器默认使用不安全的浮点优化,单元测试可能会失败。请使用标志 [`/fp:precise`](https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/fp-model-fp.html)。
该类根据 [MIT 许可证](https://opensource.org/licenses/MIT) 授权:
版权所有 © 2013-2026 [Niels Lohmann](https://nlohmann.me)
特此免费授予任何获得本软件副本和相关文档文件(“软件”)的人不受限制地处置该软件的权利,包括不受限制地使用、复制、修改、合并、发布、分发、再许可和/或出售该软件副本的权利,以及再授权被配发了本软件的人如上的权利,须在下列条件下:
上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。
本软件按“原样”提供,不提供任何形式的担保,无论是明示或暗示的担保,包括但不限于适销性、特定用途适用性和非侵权性的担保。在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是在合同诉讼、侵权行为还是其他方面,由本软件或本软件的使用或其他交易引起、由此产生或与之相关。
- 该类包含来自 Bjoern Hoehrmann 的 UTF-8 解码器,该解码器根据 [MIT 许可证](https://opensource.org/licenses/MIT) 授权(见上文)。版权所有 © 2008-2009 [Björn Hoehrmann](https://bjoern.hoehrmann.de/)
该库符合 [**REUSE 规范**](https://reuse.software) 版本 3.3:
- 每个源文件都包含 SPDX 版权页眉。
- 存储库中使用的所有许可证的全文可以在 `LICENSES` 文件夹中找到。
- 文件 `.reuse/dep5` 包含所有文件的版权和许可证概述。
- 运行 `pipx run reuse lint` 以验证项目的 REUSE 合规性,运行 `pipx run reuse spdx` 以生成 SPDX SBOM。
## 联系方式
如果你库有疑问,我想邀请你 [在 GitHub 上开启一个 issue](https://github.com/nlohmann/json/issues/new/choose)。请尽可能详细地描述你的请求、问题或疑问,并注明你正在使用的库版本以及编译器和操作系统版本。在 GitHub 上开启 issue 允许该库的其他用户和贡献者进行协作。例如,我对 MSVC 的经验很少,这方面的大多数问题都是由不断增长的社区解决的。如果你查看[已关闭的 issue](https://github.com/nlohmann/json/issues?q=is%3Aissue+is%3Aclosed),你会发现我们在大多数情况下反应相当及时。
只有当你的请求包含机密信息时,请[给我发送电子邮件](mailto:mail@nlohmann.me)。对于加密消息,请使用[此密钥](https://keybase.io/nlohmann/pgp_keys.asc)。
## 安全性
[Niels Lohmann 的提交](https://github.com/nlohmann/json/commits)和[发布版](https://github.com/nlohmann/json/releases)均使用此 [PGP 密钥](https://keybase.io/nlohmann/pgp_keys.asc?fingerprint=797167ae41c0a6d9232e48457f3cea63ae251b69)签名。
## 致谢
我深深感谢以下人员的帮助。
1. [Teemperor](https://github.com/Teemperor) 实现了 CMake 支持和 lcov 集成,实现了字符串解析器中的转义和 Unicode 处理,并修复了 JSON 序列化。
2. [elliotgoodrich](https://github.com/elliotgoodrich) 修复了迭代器类中的双重删除问题。
3. [kirkshoop](https://github.com/kirkshoop) 使类的迭代器可与其他库组合。
4. [wancw](https://github.com/wanwc) 修复了一个阻碍类使用 Clang 编译的 bug。
5. Tomas Åblad 在迭代器实现中发现了一个 bug。
6. [Joshua C. Randall](https://github.com/jrandall) 修复了浮点序列化中的一个 bug。
7. [Aaron Burghardt](https://github.com/aburgh) 实现了增量解析流的代码。此外,他通过允许定义过滤器函数在解析时丢弃不需要的元素,极大地改进了解析器类。
8. [Daniel Kopeček](https://github.com/dkopecek) 修复了使用 GCC 5.0 编译时的一个 bug。
9. [Florian Weber](https://github.com/Florianjw) 修复了比较运算符中的一个 bug 并提高了其性能。
10. [Eric Cornelius](https://github.com/EricMCornelius) 指出了处理 NaN 和无穷大值时的一个 bug。他还提高了字符串转义的性能。
11. [易思龙](https://github.com/likebeta) 实现了从匿名枚举的转换。
12. [kepkin](https://github.com/kepkin) 耐心地推动了对 Microsoft Visual Studio 的支持。
13. [gregmarr](https://github.com/gregmarr) 简化了反向迭代器的实现,并提供了许多提示和改进。特别是,他推动了用户定义类型的实现。
14. [Caio Luppi](https://github.com/caiovlp) 修复了 Unicode 处理中的一个 bug。
15. [dariomt](https://github.com/dariomt) 修复了示例中的一些拼写错误。
16. [Daniel Frey](https://github.com/d-frey) 清理了一些指针并实现了异常安全的内存分配。
17. [Colin Hirsch](https://github.com/ColinH) 处理了一个小的命名空间问题。
18. [Huu Nguyen](https://github.com/whoshuu) 更正了文档中的变量名。
19. [Silverweed](https://github.com/silverweed) 重载了 `parse()` 以接受右值引用。
20. [dariomt](https://github.com/dariomt) 修复了 MSVC 类型支持中的一个细微差别,并实现了 `get_ref()` 函数以获取对存储值的引用。
21. [ZahlGraf](https://github.com/ZahlGraf) 添加了一个允许使用 Android NDK 进行编译的变通方法。
22. [whackashoe](https://github.com/whackashoe) 替换了一个被 Visual Studio 标记为不安全的函数。
23. [406345](https://github.com/406345) 修复了两个小警告。
24. [Glen Fernandes](https://github.com/glenfe) 指出了 `has_mapped_type` 函数中潜在的移植性问题。
25. [Corbin Hughes](https://github.com/nibroc) 修复了贡献指南中的一些拼写错误。
26. [twelsby](https://github.com/twelsby) 修复了数组下标运算符、一个导致 MSVC 构建失败的问题以及浮点解析/转储。他还添加了对无符号整数的支持,并实现了更好的解析数字往返支持。
27. [Volker Diels-Grabsch](https://github.com/vog) 修复了 README 文件中的一个链接。
28. [msm-](https://github.com/msm-) 添加了对 American Fuzzy Lop 的支持。
29. [Annihil](https://github.com/Annihil) 修复了 README 文件中的一个示例。
30. [Themercee](https://github.com/Themercee) 指出了 README 文件中错误的 URL。
31. [Lv Zheng](https://github.com/lv-zheng) 修复了 `int64_t` 和 `uint64_t` 的命名空间问题。
32. [abc100m](https://github.com/abc100m) 分析了 GCC 4.8 的问题并提出了[部分解决方案](https://github.com/nlohmann/json/pull/212)。
33. [zewt](https://github.com/zewt) 在 README 文件中添加了关于 Android 的有用说明。
34. [Róbert Márki](https://github.com/robertmrk) 添加了一个修复以使用移动迭代器并通过 CMake 改进了集成。
35. [Chris Kitching](https://github.com/ChrisKitching) 清理了 CMake 文件。
36. [Tom Needham](https://github.com/06needhamt) 修复了 MSVC 2015 的一个微妙 bug,该 bug 也是由 [Michael K.](https://github.com/Epidal) 提出的。
37. [Mário Feroldi](https://github.com/thelostt) 修复了一个小拼写错误。
38. [duncanwerner](https://github.com/duncanwerner) 发现了 2.0.0 版本中一个非常令人尴尬的性能回归。
39. [Damien](https://github.com/dtoma) 修复了最后一个转换警告之一。
40. [Thomas Braun](https://github.com/t-b) 修复了测试用例中的警告并调整了 CI 中的 MSVC 调用。
41. [Théo DELRIEU](https://github.com/theodelrieu) 耐心且建设性地监督了通往[迭代器范围解析](https://github.com/nlohmann/json/issues/290)的漫长道路。他还实现了用户定义类型序列化/反序列化背后的魔法,并将单个头文件拆分为更小的块。
42. [Stefan](https://github.com/5tefan) 修复了文档中的一个小问题。
43. [Vasil Dimov](https://github.com/vasild) 修复了关于从 `std::multiset` 转换的文档。
44. [ChristophJud](https://github.com/ChristophJud) 改进了 CMake 文件以简化项目包含。
45. [Vladimir Petrigo](https://github.com/vpetrigo) 使 SFINAE hack 更具可读性,并将 Visual Studio 17 添加到构建矩阵中。
46. [Denis Andrejew](https://github.com/seeekr) 修复了 README 文件中的语法问题。
47. [Pierre-Antoine Lacaze](https://github.com/palacaze) 在 `dump()` 函数中发现了一个微妙的 bug。
48. [TurpentineDistillery](https://github.com/TurpentineDistillery) 指向 [`std::locale::classic()`](https://en.cppreference.com/w/cpp/locale/locale/classic) 以避免过多的 locale 切换,在解析器中发现了一些不错的性能改进,改进了基准测试代码,并实现了与 locale 无关的数字解析和打印。
49. [cgzones](https://github.com/cgzones) 有一个如何修复 Coverity 扫描的想法。
50. [Jared Grubb](https://github.com/jaredgrubb) 消除了一个恼人的文档警告。
51. [Yixin Zhang](https://github.com/qwename) 修复了整数溢出检查。
52. [Bosswestfalen](https://github.com/Bosswestfalen) 将两个迭代器类合并为一个更小的类。
53. [Daniel599](https://github.com/Daniel599) 帮助让 Travis 使用 Clang 的 sanitizers 执行测试。
54. [Jonathan Lee](https://github.com/vjon) 修复了 README 文件中的一个示例。
55. [gnzlbg](https://github.com/gnzlbg) 支持用户定义类型的实现。
56. [Alexej Harm](https://github.com/qis) 帮助让用户定义类型在 Visual Studio 中工作。
57. [Jared Grubb](https://github.com/jaredgrubb) 支持用户定义类型的实现。
58. [EnricoBilla](https://github.com/EnricoBilla) 指出了示例中的一个拼写错误。
59. [Martin Hořeňovský](https://github.com/horenmar) 找到了一种将测试套件的编译时间加快 2 倍的方法。
60. [ukhegg](https://github.com/ukhegg) 为示例部分提出了一项改进建议。
61. [rswanson-ihi](https://github.com/rswanson-ihi) 指出了 README 中的一个拼写错误。
62. [Mihai Stan](https://github.com/stanmihai4) 修复了与 `nullptr` 比较的一个 bug。
63. [Tushar Maheshwari](https://github.com/tusharpm) 添加了 [cotire](https://github.com/sakra/cotire) 支持以加快编译速度。
64. [TedLyngmo](https://github.com/TedLyngmo) 指出了 README 中的一个拼写错误,删除了不必要的位运算,并修复了一些 `-Weffc++` 警告。
65. [Krzysztof Woś](https://github.com/krzysztofwos) 使异常更加可见。
66. [ftillier](https://github.com/ftillier) 修复了编译器警告。
67. [tinloaf](https://github.com/tinloaf) 确保所有推入的警告都被正确弹出。
68. [Fytch](https://github.com/Fytch) 在文档中发现了一个 bug。
69. [Jay Sistar](https://github.com/Type1J) 实现了 Meson 构建描述。
70. [Henry Lee](https://github.com/HenryRLee) 修复了 ICC 中的警告并改进了迭代器实现。
71. [Vincent Thiery](https://github.com/vthiery) 维护 Conan 包管理器的包。
72. [Steffen](https://github.com/koemeet) 修复了 MSVC 和 `std::min` 的潜在问题。
73. [Mike Tzou](https://github.com/Chocobo1) 修复了一些拼写错误。
74. [amrcode](https://github.com/amrcode) 指出了关于浮点比较的误导性文档。
75. [Oleg Endo](https://github.com/olegendo) 通过用 `标签:Bash脚本, C++, Header-only, JSON, JSON for Modern C++, Modern C++, STL, 反序列化, 序列化, 开发库, 开源库, 恶意代码分析, 搜索引擎爬虫, 数据交换, 数据序列化, 数据擦除, 数据结构, 解析器, 软件开发, 配置文件