json - 新一代 C++JSON库

Created at: 2013-07-04 16:47:49
Language: C++
License: MIT

适用于现代C++的 JSON

构建状态 乌班图 苹果操作系统 窗户 覆盖范围状态 覆盖率扫描构建状态 考西徽章 卷云CI 模糊测试状态 在线试用 文档 GitHub 许可证 GitHub 发布 Vcpkg 版本 包装状态 GitHub 下载 GitHub 问题 解决问题的平均时间 关键信息基础设施最佳实践 GitHub 赞助商 重用状态 不和

设计目标

那里有无数的JSON库,每个库甚至可能有其存在的理由。我们班有以下设计目标:

  • 直观的语法。在Python等语言中,JSON感觉像是一流的数据类型。我们使用了现代C++的所有运算符魔力,在你的代码中实现了相同的感觉。看看下面的例子,你就会明白我的意思了。

  • 琐碎的集成。我们的整个代码由一个头文件 json.hpp 组成。就是这样。没有库,没有子项目,没有依赖项,没有复杂的构建系统。该类是用 Vanilla C++11编写的。总而言之,一切都不需要调整编译器标志或项目设置。

  • 认真测试。我们的代码经过严格的单元测试,涵盖了 100% 的代码,包括所有异常行为。此外,我们与ValgrindClang Sanitizers进行了检查,没有内存泄漏。Google OSS-Fuzz 还对所有解析器运行模糊测试,每周 7 天、每天 24 小时,到目前为止有效地执行了数十亿次测试。为了保持高质量,该项目遵循核心基础设施倡议(CII)的最佳实践

其他方面对我们来说并不那么重要:

  • 内存效率。每个 JSON 对象的开销为一个指针(联合的最大大小)和一个枚举元素(1 个字节)。默认泛化使用以下C++数据类型:字符串、数字、对象、数组和布尔值。但是,你可以根据需要模板化类。

    std::string
    int64_t
    uint64_t
    double
    std::map
    std::vector
    bool
    basic_json

  • 速度。当然有更快的JSON库。但是,如果你的目标是通过使用单个标头添加 JSON 支持来加快开发速度,那么此库就是你的最佳选择。如果你知道如何使用 或 ,则你已经设置好了。

    std::vector
    std::map

有关详细信息,请参阅贡献指南

赞助商

你可以在 GitHub Sponsors 上赞助此库。

🏢 企业赞助商

🏷️ 指定赞助商

谢谢大家!

支持

❓ 如果你有问题,请检查是否已在常见问题解答问答部分回答。如果没有,请在那里提出一个新问题

📚 如果你想了解有关如何使用该库的更多信息,请查看自述文件的其余部分,查看代码示例或浏览帮助页面

🚧 如果你想更好地了解 API,请查看 API 参考

🐛 如果你发现错误,请查看常见问题解答,如果它是已知问题还是设计决策的结果。在创建新问题之前,还请查看问题列表。请提供尽可能多的信息,以帮助我们了解和重现你的问题。

还有一个用于文档浏览器 DashVelocityZeal 的文档,其中包含完整的文档作为离线资源。

例子

下面是一些示例,可让你了解如何使用该类。

除了以下示例之外,你可能还需要:

→ 查看文档
→浏览独立示例文件

每个 API 函数(记录在 API 文档中)都有一个相应的独立示例文件。例如,emplace() 函数有一个匹配的 emplace.cpp 示例文件。

从文件中读取 JSON

该类提供了一个用于操作 JSON 值的 API。要通过读取 JSON 文件创建对象,请执行以下操作:

json
json

#include <fstream>
#include <nlohmann/json.hpp>
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 that is stored as double (note the implicit conversion of j to an object)
j["pi"] = 3.141;

// add a Boolean that is stored as bool
j["happy"] = true;

// add a string that is 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 that is 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()和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 }"

字符串文字应该被纳入范围(参见 json::p arse())。

using namespace nlohmann::literals;

上面的例子也可以用json::p arse()显式表示:

// 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.template get<std::string>();
// 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.template get<std::string>() << '\n';
// output of serialized value
std::cout << j_string << " == " << serialized_string << std::endl;

.dump() 返回最初存储的字符串值。

请注意,该库仅支持 UTF-8。当你在库中存储具有不同编码的字符串时,调用 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;也就是说,从迭代器可访问的任何容器中,迭代器是 1、2 或 4 字节的整数类型,将分别解释为 UTF-8、UTF-16 和 UTF-32。例如,a 或 :

value_type
std::vector<std::uint8_t>
std::list<std::uint16_t>

std::vector<std::uint8_t> v = {'t', 'r', 'u', 'e'};
json j = json::parse(v.begin(), v.end());

你可以将迭代器保留在范围 [开始, 结束):

std::vector<std::uint8_t> v = {'t', 'r', 'u', 'e'};
json j = json::parse(v);

自定义数据源

由于 parse 函数接受任意迭代器范围,因此你可以通过实现该概念来提供自己的数据源。

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++() {
        MyContainer.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 的接口:

// 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<json>
  2. 创建 SAX 接口类的对象,例如 .
    my_sax
  3. 叫;其中第一个参数可以是任何输入,如字符串或输入流,第二个参数是指向 SAX 接口的指针。
    bool json::sax_parse(input, &my_sax)

请注意,该函数仅返回指示上次执行的 SAX 事件的结果。它不返回值 - 由你决定如何处理 SAX 事件。此外,在发生解析错误时不会引发异常 - 如何处理传递给实现的异常对象取决于你。在内部,SAX 接口用于 DOM 解析器(类)和接受器(),请参阅文件 json_sax.hpp

sax_parse
bool
json
parse_error
json_sax_dom_parser
json_sax_acceptor

类似 STL 的访问

我们将 JSON 类设计为类似于 STL 容器的行为。事实上,它满足可逆容器的要求。

// 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].template get<std::string>();
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 容器转换

任何其值可用于构造 JSON 值(例如,整数、浮点数、布尔值、字符串类型或本节中描述的 STL 容器)的序列容器 (、、) 都可用于创建 JSON 数组。这同样适用于类似的关联容器 (, , , ),但在这些情况下,数组元素的顺序取决于元素在相应 STL 容器中的排序方式。

std::array
std::vector
std::deque
std::forward_list
std::list
std::set
std::multiset
std::unordered_set
std::unordered_multiset

std::vector<int> c_vector {1, 2, 3, 4};
json j_vec(c_vector);
// [1, 2, 3, 4]

std::deque<double> 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<bool> c_list {true, true, false, true};
json j_list(c_list);
// [true, true, false, true]

std::forward_list<int64_t> c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543};
json j_flist(c_flist);
// [12345678909876, 23456789098765, 34567890987654, 45678909876543]

std::array<unsigned long, 4> c_array {{1, 2, 3, 4}};
json j_array(c_array);
// [1, 2, 3, 4]

std::set<std::string> 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<std::string> 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<std::string> 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<std::string> c_umset {"one", "two", "one", "four"};
json j_umset(c_umset); // both entries for "one" are used
// maybe ["one", "two", "one", "four"]

同样,任何关联键值容器 (, , , ) 其键可以构造 并且其值可用于构造 JSON 值(请参阅上面的示例)都可用于创建 JSON 对象。请注意,在多重映射的情况下,JSON 对象中仅使用一个键,该值取决于 STL 容器的内部顺序。

std::map
std::multimap
std::unordered_map
std::unordered_multimap
std::string

std::map<std::string, int> c_map { {"one", 1}, {"two", 2}, {"three", 3} };
json j_map(c_map);
// {"one": 1, "three": 3, "two": 2 }

std::unordered_map<const char*, double> 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<std::string, bool> 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<std::string, bool> 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 指针和 JSON 补丁

该库支持 JSON 指针RFC 6901) 作为处理结构化值的替代方法。最重要的是,JSON PatchRFC 6902)允许描述两个JSON值之间的差异 - 有效地允许Unix已知的补丁和差异操作。

// 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 合并补丁

该库支持 JSON 合并修补程序 (RFC 7386) 作为修补程序格式。它不是使用 JSON 指针(见上文)来指定要操作的值,而是使用与正在修改的文档非常相似的语法来描述更改。

// 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 值隐式转换。你可以在此处找到有关此建议的更多详细信息。你可以通过在包含标头之前定义 to 来关闭隐式转换。使用 CMake 时,还可以通过将选项设置为 .

JSON_USE_IMPLICIT_CONVERSIONS
0
json.hpp
JSON_ImplicitConversions
OFF

// strings
std::string s1 = "Hello, world!";
json js = s1;
auto s2 = js.template get<std::string>();
// NOT RECOMMENDED
std::string s3 = js;
std::string s4;
s4 = js;

// Booleans
bool b1 = true;
json jb = b1;
auto b2 = jb.template get<bool>();
// NOT RECOMMENDED
bool b3 = jb;
bool b4;
b4 = jb;

// numbers
int i = 42;
json jn = i;
auto f = jn.template get<double>();
// NOT RECOMMENDED
double f2 = jb;
double f3;
f3 = jb;

// etc.

请注意,类型不会自动转换为 JSON 字符串,而是转换为整数。必须显式指定对字符串的转换:

char

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"].template get<std::string>(),
    j["address"].template get<std::string>(),
    j["age"].template get<int>()
};

它有效,但这是相当多的样板...幸运的是,有一个更好的方法:

// 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.template get<ns::person>();

// 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

就这样!使用类型调用构造函数时,将自动调用自定义方法。同样,调用 or 时,将调用该方法。

json
to_json
template get<your_type>()
get_to(your_type&)
from_json

一些重要的事情:

  • 这些方法必须位于类型的命名空间(可以是全局命名空间)中,否则库将无法找到它们(在此示例中,它们位于命名空间中,其中定义了)。
    ns
    person
  • 这些方法必须在你使用这些转换的任何地方可用(例如,必须包含正确的标头)。查看问题 1108 以了解可能发生的错误。
  • 使用 时,必须DefaultConstructable。(有一种方法可以绕过后面介绍的此要求。
    template get<your_type>()
    your_type
  • 在函数中,使用函数 at() 而不是 访问对象值。如果键不存在,则引发可以处理的异常,而表现出未定义的行为。
    from_json
    operator[]
    at
    operator[]
  • 你不需要为 STL 类型添加序列化程序或反序列化程序,例如:库已经实现了这些。
    std::vector

使用宏简化你的生活

如果你只想序列化/反序列化一些结构,/ 函数可以是很多样板。

to_json
from_json

有两个宏可以让你的生活更轻松,只要你 (1) 想要使用 JSON 对象作为序列化,并且 (2) 想要使用成员变量名称作为该对象中的对象键:

  • NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...)
    将在要为其创建代码的类/结构的命名空间内定义。
  • NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...)
    将在要为其创建代码的类/结构中定义。此宏还可以访问私有成员。

在这两个宏中,第一个参数是类/结构的名称,其余所有参数都命名成员。

例子

上述结构的 / 函数可以通过以下方式创建:

to_json
from_json
person

namespace ns {
    NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age)
}

下面是一个需要私有成员的示例:

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 序列化程序将类型转换为 json。的默认序列化程序是(ADL 表示 依赖于参数的查找)。

nlohmann::json
nlohmann::adl_serializer

它是这样实现的(简化):

template <typename T>
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
    }
};

当你控制类型的命名空间时,此序列化程序工作正常。但是,或(C++17)呢?劫持命名空间非常糟糕,将模板专用化以外的内容添加到...

boost::optional
std::filesystem::path
boost
std

要解决此问题,你需要向命名空间添加专用化,下面是一个示例:

adl_serializer
nlohmann

// partial specialization (full specialization works too)
namespace nlohmann {
    template <typename T>
    struct adl_serializer<boost::optional<T>> {
        static void to_json(json& j, const boost::optional<T>& opt) {
            if (opt == boost::none) {
                j = nullptr;
            } else {
              j = *opt; // this will call adl_serializer<T>::to_json which will
                        // find the free function to_json in T's namespace!
            }
        }

        static void from_json(const json& j, boost::optional<T>& opt) {
            if (j.is_null()) {
                opt = boost::none;
            } else {
                opt = j.template get<T>(); // same as above, but with
                                           // adl_serializer<T>::from_json
            }
        }
    };
}

如何将 get() 用于非默认的可构造/不可复制类型?

有一种方法,如果你的类型是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<move_only_type> {
        // 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.template get<int>()};
        }

        // 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以查看一些示例。

如果编写自己的序列化程序,则需要执行以下几项操作:

  • 使用与 (的最后一个模板参数是
    basic_json
    nlohmann::json
    basic_json
    JSONSerializer
    )
  • 在所有 / 方法中使用别名(或模板参数)
    basic_json
    to_json
    from_json
  • 使用以及何时需要 ADL
    nlohmann::to_json
    nlohmann::from_json

下面是一个示例,无需简化,它仅接受大小为 <= 32 的类型,并使用 ADL。

// You should use void as a second template argument
// if you don't need compile-time checks on T
template<typename T, typename SFINAE = typename std::enable_if<sizeof(T) <= 32>::type>
struct less_than_32_serializer {
    template <typename BasicJsonType>
    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 <typename BasicJsonType>
    static void from_json(const BasicJsonType& j, T& value) {
        // same thing here
        using nlohmann::from_json;
        from_json(j, value);
    }
};

重新实现序列化程序时要非常小心,如果不注意,可能会堆叠溢出:

template <typename T, void>
struct bad_serializer
{
    template <typename BasicJsonType>
    static void to_json(BasicJsonType& j, const T& value) {
      // this calls BasicJsonType::json_serializer<T>::to_json(j, value);
      // if BasicJsonType::json_serializer == bad_serializer ... oops!
      j = value;
    }

    template <typename BasicJsonType>
    static void to_json(const BasicJsonType& j, T& value) {
      // this calls BasicJsonType::json_serializer<T>::from_json(j, value);
      // if BasicJsonType::json_serializer == bad_serializer ... oops!
      value = j.template get<T>(); // 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()
to_json()
from_json()
TaskState

用法:

// enum to JSON as string
json j = TS_STOPPED;
assert(j == "stopped");

// json string to enum
json j3 = "running";
assert(j3.template get<TaskState>() == TS_RUNNING);

// undefined json value to enum (where the first map entry above is the default)
json jPi = 3.14;
assert(jPi.template get<TaskState>() == TS_INVALID );

就像上面的任意类型转换一样,

  • NLOHMANN_JSON_SERIALIZE_ENUM()
    必须在枚举类型的命名空间(可以是全局命名空间)中声明,否则库将无法找到它,并且它将默认为整数序列化。
  • 它必须在你使用转换的任何地方可用(例如,必须包含正确的标头)。

其他要点:

  • 使用 时,未定义的 JSON 值将默认为映射中指定的第一对。请仔细选择此默认对。
    template get<ENUM_TYPE>()
  • 如果在映射中多次指定枚举或 JSON 值,则在转换为 JSON 或从 JSON 转换时,将返回映射顶部的第一个匹配项。

二进制格式(BSON,CBOR,MessagePack,UBJSON和BJData)

虽然JSON是一种无处不在的数据格式,但它不是一种非常紧凑的格式,适合数据交换,例如通过网络。因此,该库支持BSON(二进制JSON),CBOR(简洁二进制对象表示),MessagePack,UBJSON(通用二进制JSON规范)和BJData(二进制JData),以有效地将JSON值编码为字节向量并解码此类向量。

// create a JSON value
json j = R"({"compact": true, "schema": 0})"_json;

// serialize to BSON
std::vector<std::uint8_t> 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<std::uint8_t> 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<std::uint8_t> 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<std::uint8_t> 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<std::uint8_t>

// CBOR byte string with payload 0xCAFE
std::vector<std::uint8_t> 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<std::uint8_t> 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

支持的编译器

虽然已经是 2023 年了,但对 C++11 的支持仍然有点稀疏。目前,已知以下编译器可以工作:

  • GCC 4.8 - 12.0(可能更高版本)
  • Clang 3.4 - 15.0(可能更高版本)
  • Apple Clang 9.1 - 13.1(可能更高版本)
  • 英特尔C++编译器 17.0.2(可能更高版本)
  • Nvidia CUDA Compiler 11.0.221(可能更高版本)
  • Microsoft Visual C++ 2015 / 生成工具 14.0.25123.0(及可能更高版本)
  • Microsoft Visual C++ 2017 / 生成工具 15.5.180.51428(可能更高版本)
  • Microsoft Visual C++ 2019 / 构建工具 16.3.1+1def00d3d(可能更高版本)
  • Microsoft Visual C++ 2022 / 构建工具 19.30.30709.0(可能更高版本)

我很乐意了解其他编译器/版本。

请注意:

  • GCC 4.8 有一个错误 57824):多行原始字符串不能是宏的参数。不要使用此编译器直接在宏中使用多行原始字符串。

  • Android 默认使用非常旧的编译器和C++库。要解决此问题,请将以下内容添加到你的 .这将切换到 LLVM C++库、Clang 编译器,并启用 C++11 和其他默认禁用的功能。

    Application.mk

    APP_STL := c++_shared
    NDK_TOOLCHAIN_VERSION := clang3.6
    APP_CPPFLAGS += -frtti -fexceptions
    

    该代码与Android NDK修订版9 - 11(可能更高版本)和CrystaX的Android NDK版本10成功编译。

  • 对于在MinGW或Android SDK上运行的GCC,可能会出现错误(或类似的,for或)。请注意,这不是代码的问题,而是编译器本身的问题。在 Android 上,请参阅上文以使用较新的环境进行构建。对于 MinGW,请参阅此站点此讨论以获取有关如何修复此错误的信息。对于使用 的 Android NDK,请参阅此讨论

    'to_string' is not a member of 'std'
    strtod
    strtof
    APP_STL := gnustl_static

  • 不受支持的 GCC 和 Clang 版本被指令拒绝。这可以通过定义来关闭。请注意,在这种情况下,你可以期望不支持。

    #error
    JSON_SKIP_UNSUPPORTED_COMPILER_CHECK

以下编译器目前用于 AppVeyorCirrus CIGitHub Actions 的持续集成:

编译器 操作系统 CI 提供程序
苹果叮当 11.0.3 (clang-1103.0.32.62);Xcode 11.7 macOS 11.7.1 GitHub 操作
苹果叮当 12.0.0 (clang-1200.0.32.29);Xcode 12.4 macOS 11.7.1 GitHub 操作
苹果叮当 12.0.5 (叮当-1205.0.22.11);Xcode 12.5.1 macOS 11.7.1 GitHub 操作
苹果叮当 13.0.0 (叮当-1300.0.29.3);Xcode 13.0 macOS 11.7.1 GitHub 操作
苹果叮当 13.0.0 (叮当-1300.0.29.3);Xcode 13.1 macOS 12.6.1 GitHub 操作
苹果叮当 13.0.0 (叮当-1300.0.29.30);Xcode 13.2.1 macOS 12.6.1 GitHub 操作
苹果叮当 13.1.6 (clang-1316.0.21.2.3);Xcode 13.3.1 macOS 12.6.1 GitHub 操作
苹果叮当 13.1.6 (叮当-1316.0.21.2.5);Xcode 13.4.1 macOS 12.6.1 GitHub 操作
苹果叮当 14.0.0 (叮当-1400.0.29.102);Xcode 14.0 macOS 12.6.1 GitHub 操作
苹果叮当 14.0.0 (叮当-1400.0.29.102);Xcode 14.0.1 macOS 12.6.1 GitHub 操作
苹果叮当 14.0.0 (clang-1400.0.29.202);Xcode 14.1 macOS 12.6.1 GitHub 操作
叮当 3.5.2 优麒麟 20.04.3 LTS GitHub 操作
叮当 3.6.2 优麒麟 20.04.3 LTS GitHub 操作
叮当 3.7.1 优麒麟 20.04.3 LTS GitHub 操作
叮当 3.8.1 优麒麟 20.04.3 LTS GitHub 操作
叮当 3.9.1 优麒麟 20.04.3 LTS GitHub 操作
叮当 4.0.1 优麒麟 20.04.3 LTS GitHub 操作
叮当 5.0.2 优麒麟 20.04.3 LTS GitHub 操作
叮当 6.0.1 优麒麟 20.04.3 LTS GitHub 操作
叮当 7.0.1 优麒麟 20.04.3 LTS GitHub 操作
叮当 8.0.0 优麒麟 20.04.3 LTS GitHub 操作
叮当 9.0.0 优麒麟 20.04.3 LTS GitHub 操作
叮当 10.0.0 优麒麟 20.04.3 LTS GitHub 操作
Clang 10.0.0 与类似 GNU 的命令行 视窗-10.0.17763 GitHub 操作
Clang 11.0.0 与类似 GNU 的命令行 视窗-10.0.17763 GitHub 操作
Clang 11.0.0 与类似 MSVC 的命令行 视窗-10.0.17763 GitHub 操作
叮当 11.0.0 优麒麟 20.04.3 LTS GitHub 操作
叮当 12.0.0 优麒麟 20.04.3 LTS GitHub 操作
Clang 12.0.0 与类似 GNU 的命令行 视窗-10.0.17763 GitHub 操作
叮当 13.0.0 优麒麟 20.04.3 LTS GitHub 操作
Clang 13.0.0 与类似 GNU 的命令行 视窗-10.0.17763 GitHub 操作
叮当 14.0.0 优麒麟 20.04.3 LTS GitHub 操作
Clang 14.0.0 与类似 GNU 的命令行 视窗-10.0.17763 GitHub 操作
Clang 15.0.0 与类似 GNU 的命令行 视窗-10.0.17763 GitHub 操作
叮当 15.0.4 优麒麟 20.04.3 LTS GitHub 操作
Clang 16.0.0 (16.0.0-++20221031071727+500876226c60-1exp120221031071831.439) 优麒麟 20.04.3 LTS GitHub 操作
GCC 4.8.5 (Ubuntu 4.8.5-4ubuntu2) 优麒麟 20.04.3 LTS GitHub 操作
海湾合作委员会 4.9.4 优麒麟 20.04.3 LTS GitHub 操作
海湾合作委员会 5.5.0 优麒麟 20.04.3 LTS GitHub 操作
海湾合作委员会 6.5.0 优麒麟 20.04.3 LTS GitHub 操作
海湾合作委员会 7.5.0 优麒麟 20.04.3 LTS GitHub 操作
GCC 8.1.0 (i686-posix-dwarf-rev0,由MinGW-W64项目构建) 视窗-10.0.17763 GitHub 操作
GCC 8.1.0 (x86_64-posix-she-rev0, 由MinGW-W64项目构建) 视窗-10.0.17763 GitHub 操作
海湾合作委员会 8.5.0 优麒麟 20.04.3 LTS GitHub 操作
海湾合作委员会 9.5.0 优麒麟 20.04.3 LTS GitHub 操作
海湾合作委员会 10.4.0 优麒麟 20.04.3 LTS GitHub 操作
海湾合作委员会 11.1.0 Ubuntu (aarch64) 卷云CI
海湾合作委员会 11.3.0 优麒麟 20.04.3 LTS GitHub 操作
海湾合作委员会 12.2.0 优麒麟 20.04.3 LTS GitHub 操作
GCC 13.0.0 20220605(实验性) 优麒麟 20.04.3 LTS GitHub 操作
英特尔C++编译器 2021.5.0.20211109 优麒麟 20.04.3 LTS GitHub 操作
NVCC 11.0.221 优麒麟 20.04.3 LTS GitHub 操作
Visual Studio 14 2015 MSVC 19.0.24241.7(生成引擎版本 14.0.25420.1) 视窗-6.3.9600 AppVeyor
Visual Studio 15 2017 MSVC 19.16.27035.0(Build Engine version 15.9.21+g9802d43bc3 for .NET Framework) 视窗-10.0.14393 AppVeyor
Visual Studio 16 2019 MSVC 19.28.29912.0(Build Engine version 16.9.0+57a23d249 for .NET Framework) 视窗-10.0.17763 GitHub 操作
Visual Studio 16 2019 MSVC 19.28.29912.0(Build Engine version 16.9.0+57a23d249 for .NET Framework) 视窗-10.0.17763 AppVeyor
Visual Studio 17 2022 MSVC 19.30.30709.0(适用于 .NET Framework 的构建引擎版本 17.0.31804.368) 视窗-10.0.20348 GitHub 操作

集成

json.hpp 是此处发布或发布的唯一必需文件。你需要添加

single_include/nlohmann

#include <nlohmann/json.hpp>

// for convenience
using json = nlohmann::json;

到要处理 JSON 的文件,并设置必要的开关以启用 C++11(例如,用于 GCC 和 Clang)。

-std=c++11

你可以进一步使用文件 include/nlohmann/json_fwd.hpp 进行前向声明。json_fwd.hpp 的安装(作为 cmake 安装步骤的一部分),可以通过设置 .

-DJSON_MultipleHeaders=ON

清明

你还可以在 CMake 中使用接口目标。此目标填充相应的使用要求,以指向相应的包含目录和必要的 C++11 标志。

nlohmann_json::nlohmann_json
INTERFACE_INCLUDE_DIRECTORIES
INTERFACE_COMPILE_FEATURES

外部

若要从 CMake 项目中使用此库,可以直接使用生成的包配置中导入的命名空间目标找到它并使用它:

find_package()

# CMakeLists.txt
find_package(nlohmann_json 3.2.0 REQUIRED)
...
add_library(foo ...)
...
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)

软件包配置文件 可以从安装树中使用,也可以直接从构建树中使用。

nlohmann_jsonConfig.cmake

嵌入式

要将库直接嵌入到现有 CMake 项目中,请将整个源代码树放在子目录中并调用文件:

add_subdirectory()
CMakeLists.txt

# 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)
嵌入式(获取内容)

从 CMake v3.11 开始,FetchContent 可用于在配置时自动下载版本作为依赖项。

例:

include(FetchContent)

FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.11.2/json.tar.xz)
FetchContent_MakeAvailable(json)

target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)

注意:建议使用上述 URL 方法,该方法从版本 3.10.0 开始受支持。有关详细信息,请参阅 https://json.nlohmann.me/integration/cmake/#fetchcontent

支持两者

要允许项目支持外部提供的或嵌入式 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.2.0 REQUIRED)
else()
  set(JSON_BuildTests OFF CACHE INTERNAL "")
  add_subdirectory(nlohmann_json)
endif()
...

thirdparty/nlohmann_json
然后是此源代码树的完整副本。

包管理器

🍺 如果你使用的是OS X和Homebrew,只需键入即可设置。如果需要最前沿而不是最新版本,请使用 。有关更多信息,请参阅 nlohmann-json

brew install nlohmann-json
brew install nlohmann-json --HEAD

如果你使用的是介子构建系统,请将此源代码树添加为介子子项目。你还可以使用此项目版本中发布的版本来减小供应商源代码树的大小。或者,你可以通过从 Meson WrapDB 下载一个包装文件来获取它,或者简单地使用 .有关包装的任何问题,请参阅介子项目。

include.zip
meson wrap install nlohmann_json

提供的也可以用作 CMake 的替代方法,用于在系统范围内安装,在这种情况下,将安装 pkg 配置文件。要使用它,只需让你的构建系统需要 pkg 配置依赖项即可。在 Meson 中,最好将 dependency() 对象与子项目回退一起使用,而不是直接使用子项目。

meson.build
nlohmann_json
nlohmann_json

如果你使用的是 Bazel,则可以简单地使用 或 引用此存储库,并依赖于 。

http_archive
git_repository
@nlohmann_json//:json

如果使用 Conan 管理依赖项,只需将 nlohmann_json/x.y.z 添加到 的要求中,即要使用的发布版本在哪里。如果你在使用软件包时遇到问题,请在此处提交问题。

conanfile
x.y.z

如果你使用 Spack 来管理依赖项,则可以使用 nlohmann-json 包。有关包装的任何问题,请参阅spack项目

如果在项目上使用 hunter 作为外部依赖项,则可以使用 nlohmann_json 包。有关包装的任何问题,请参阅猎人项目。

如果你使用的是 Buckaroo,则可以使用 .请在此处提交问题。这里有一个演示存储库。

buckaroo add github.com/buckaroo-pm/nlohmann-json

如果你在项目上使用 vcpkg 作为外部依赖项,则可以使用 并按照当时显示的说明安装 nlohmann-json 包。有关打包的任何问题,请参阅 vcpkg 项目。

vcpkg install nlohmann-json

如果你使用的是 cget,则可以使用 .可以使用 安装特定版本。此外,可以通过添加标志(即 )来安装多标头版本。

cget install nlohmann/json
cget install nlohmann/json@v3.1.0
-DJSON_MultipleHeaders=ON
cget install nlohmann/json -DJSON_MultipleHeaders=ON

如果你使用的是 CocoaPods,则可以通过将 pod 添加到 pod 文件来使用该库(请参阅示例)。请在此处提交问题。

"nlohmann_json", '~>3.1.2'

如果使用的是NuGet,则可以使用包nlohmann.json。请查看有关如何使用该软件包的广泛说明。请在此处提交问题。

如果你使用的是 conda,则可以使用 conda-forge 执行中的包nlohmann_json。请在此处提交问题。

conda install -c conda-forge nlohmann_json

如果你使用的是MSYS2,你可以使用mingw-w64-nlohmann-json包,只需键入或进行安装。如果你在使用软件包时遇到问题,请在此处提交问题。

pacman -S mingw-w64-i686-nlohmann-json
pacman -S mingw-w64-x86_64-nlohmann-json

如果你使用的是 MacPorts,请执行以安装 nlohmann-json 软件包。

sudo port install nlohmann-json

如果你使用的是 build2,则可以从公共存储库 https://cppget.org 或直接从包的源存储库使用 nlohmann-json 包。在项目的文件中,只需添加(可能有一些版本限制)。如果你不熟悉在 中使用依赖项,请阅读此介绍。如果你在使用软件包时遇到问题,请在此处提交问题。

manifest
depends: nlohmann-json
build2

如果你使用的是 wsjcpp,则可以使用该命令获取最新版本。请注意,你可以将分支“:d evelop”更改为现有标记或其他分支。

wsjcpp install "https://github.com/nlohmann/json:develop"

如果你使用的是CPM.cmake,则可以查看此示例将 CPM 脚本添加到项目后,将以下代码片段实现到 CMake:

CPMAddPackage(
    NAME nlohmann_json
    GITHUB_REPOSITORY nlohmann/json
    VERSION 3.9.1)

Pkg-config

如果你使用的是裸生成文件,则可以使用 生成指向库安装位置的包含标志:

pkg-config

pkg-config nlohmann_json --cflags

Meson构建系统的用户也将能够使用系统范围的库,该库可通过以下方式找到:

pkg-config

json = dependency('nlohmann_json', required: true)

许可证

该类根据 MIT 许可证获得许可:

版权所有 © 2013-2022 尼尔斯·罗曼

特此免费授予获得本软件和相关文档文件(“软件”)副本的任何人不受限制地处理本软件的权限,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售本软件副本的权利,并允许向其提供本软件的人这样做, 须符合以下条件:

上述版权声明和本许可声明应包含在软件的所有副本或大部分内容中。

本软件按“原样”提供,不提供任何明示或暗示的保证,包括但不限于适销性、特定用途适用性和不侵权的保证。在任何情况下,作者或版权所有者均不对因本软件或本软件的使用或其他交易而引起、产生或与之相关的任何索赔、损害赔偿或其他责任负责,无论是在合同、侵权或其他诉讼中。


该类包含来自Bjoern Hoehrmann的UTF-8解码器,该解码器根据MIT许可证获得许可(见上文)。版权所有 © 2008-2009 比约恩·霍尔曼 bjoern@hoehrmann.de

该类包含来自Florian Loitsch的Grisu2算法的略微修改版本,该算法在MIT许可证下获得许可(见上文)。版权所有 © 2009 弗洛里安·洛伊奇

该类包含来自 Evan Nemerson 的 Hedley 副本,该副本的许可为 CC0-1.0

该类包含Google Abseil的部分内容,该部分内容在Apache 2.0许可证下获得许可。

联系

如果你对库有疑问,我想邀请你在 GitHub 上提出一个问题。请尽可能详细地描述你的请求、问题或疑问,并提及你正在使用的库版本以及编译器和操作系统的版本。在 GitHub 上打开问题允许此库的其他用户和贡献者进行协作。例如,我对MSVC几乎没有经验,这方面的大多数问题都已由不断增长的社区解决。如果你查看已关闭的问题,你会发现我们在大多数情况下 React 非常及时。

仅当你的请求包含机密信息时,请给我发送电子邮件。对于加密邮件,请使用此密钥

安全

Niels Lohmann 的提交版本使用此 PGP 密钥进行签名。

谢谢

我非常感谢以下人员的帮助。

  1. Teemperor 实现了 CMake 支持和 lcov 集成,在字符串解析器中实现了转义和 Unicode 处理,并修复了 JSON 序列化。
  2. elliotgoodrich 修复了迭代器类中的双重删除问题。
  3. kirkshoop 使该类的迭代器可组合到其他库中。
  4. wancw 修复了一个阻碍类使用 Clang 编译的错误。
  5. Tomas Åblad 在迭代器实现中发现了一个错误。
  6. Joshua C. Randall 修复了浮点序列化中的一个错误。
  7. Aaron Burghardt 实现了以增量方式解析流的代码。此外,他通过允许过滤器函数的定义在解析时丢弃不需要的元素,极大地改进了解析器类。
  8. Daniel Kopeček修复了GCC 5.0编译中的一个错误。
  9. Florian Weber 修复了一个错误并改进了比较运算符的性能。
  10. Eric Cornelius指出了处理NaN和无穷大值的一个错误。他还改进了字符串逃逸的性能。
  11. 易思龙实现了从匿名枚举的转换。
  12. kepkin耐心地推动了对Visual Studio的支持Microsoft。
  13. Gregmarr 简化了反向迭代器的实现,并提供了许多提示和改进。特别是,他推动了用户定义类型的实现。
  14. Caio Luppi 修复了 Unicode 处理中的一个错误。
  15. dariomt 修复了示例中的一些拼写错误。
  16. Daniel Frey 清理了一些指针并实现了异常安全的内存分配。
  17. Colin Hirsch 负责处理一个小的命名空间问题。
  18. Huu Nguyen 更正文档中的变量名称。
  19. 银草超载以接受右值引用。
    parse()
  20. dariomt 修复了 MSVC 类型支持中的细微之处,并实现了该函数以获取对存储值的引用。
    get_ref()
  21. ZahlGraf添加了一种解决方法,允许使用Android NDK进行编译。
  22. whackashoe替换了一个被Visual Studio标记为不安全的功能。
  23. 406345修复了两个小警告。
  24. Glen Fernandes指出了该功能中潜在的可移植性问题。
    has_mapped_type
  25. Corbin Hughes修复了贡献指南中的一些拼写错误。
  26. Twelsby 修复了数组下标运算符、MSVC 生成失败的问题以及浮点分析/转储。他进一步增加了对无符号整数的支持,并对解析的数字实现了更好的往返支持。
  27. Volker Diels-Grabsch 修复了自述文件中的链接。
  28. msm- 添加了对American Fuzzy Lop的支持。
  29. Annihil 修复了自述文件中的示例。
  30. Themercee 在自述文件中注意到一个错误的 URL。
  31. 吕郑修复了 和 的命名空间问题。
    int64_t
    uint64_t
  32. abc100m分析了GCC 4.8的问题,并提出了部分解决方案
  33. zewt 在关于 Android 的自述文件中添加了有用的注释。
  34. Róbert Márki 添加了使用移动迭代器的修复程序,并通过 CMake 改进了集成。
  35. Chris Kitching清理了CMake文件。
  36. Tom Needham修复了MSVC 2015的一个微妙错误,这也是由Michael K.提出的。
  37. 马里奥·费罗尔迪修正了一个小错别字。
  38. duncanwerner 在 2.0.0 版本中发现了一个非常令人尴尬的性能回归。
  39. 戴缅恩修复了最后的转换警告之一。
  40. Thomas Braun 在测试用例中修复了一个警告,并调整了 CI 中的 MSVC 调用。
  41. Théo DELRIEU 耐心而建设性地监督了迭代器范围解析的漫长道路。他还实现了用户定义类型的序列化/反序列化背后的魔力,并将单个头文件拆分为较小的块。
  42. Stefan 修复了文档中的一个小问题。
  43. 瓦西尔·迪莫夫修复了有关从 转换的文档。
    std::multiset
  44. ChristophJud 过度处理 CMake 文件以简化项目包含。
  45. Vladimir Petrigo使SFINAE黑客更具可读性,并将Visual Studio 17添加到构建矩阵中。
  46. Denis Andrejew 修复了自述文件中的语法问题。
  47. Pierre-Antoine Lacaze在函数中发现了一个微妙的错误。
    dump()
  48. 松节油蒸馏厂指出 std::locale::classic() 以避免过多的语言环境慢跑,在解析器中发现了一些不错的性能改进,改进了基准代码,并实现了与语言环境无关的数字解析和打印。
  49. cgzones有一个想法,如何修复Coverity扫描。
  50. 贾里德·格拉布(Jared Grubb)压制了一个令人讨厌的文档警告。
  51. 张一新修复了整数溢出检查。
  52. Bosswestfalen 将两个迭代器类合并为一个较小的类。
  53. Daniel599帮助Travis使用Clang的消毒剂执行测试。
  54. Jonathan Lee 修复了自述文件中的示例。
  55. gnzlbg 支持用户定义类型的实现。
  56. Alexej Harm帮助用户定义的类型与Visual Studio一起工作。
  57. Jared Grubb 支持用户定义类型的实现。
  58. EnricoBilla在一个例子中指出了一个错别字。
  59. Martin Hořeňovský 找到了一种方法,将测试套件的编译时间提高了 2 倍。
  60. ukhegg发现对示例部分提出了改进建议。
  61. rswanson-IHI注意到自述文件中的一个错别字。
  62. Mihai Stan 修复了与 s 比较中的一个错误。
    nullptr
  63. Tushar Maheshwari增加了cotire支持以加快编译速度。
  64. TedLyngmo注意到自述文件中的一个拼写错误,删除了不必要的位算术,并修复了一些警告。
    -Weffc++
  65. Krzysztof Woś使例外更加明显。
  66. ftillier修复了编译器警告。
  67. tinloaf确保所有推送的警告都正确弹出。
  68. Fytch 在文档中发现了一个错误。
  69. Jay Sistar实现了Meson构建描述。
  70. Henry Lee 修复了 ICC 中的警告并改进了迭代器实现。
  71. Vincent Thiery 为 Conan 包管理器维护一个包。
  72. Steffen 修复了 MSVC 和 的潜在问题。
    std::min
  73. Mike Tzou修正了一些错别字。
  74. amrcode注意到一个关于浮点数比较的误导性文档。
  75. Oleg Endo 通过替换为 来减少内存消耗。
    <iostream>
    <iosfwd>
  76. dan-42清理了CMake文件,以简化库的包含/重用。
  77. Nikita Ofitserov允许从初始值设定项列表中移动值。
  78. Greg Hurrell修正了一个错别字。
  79. 德米特里·库科维内茨修正了一个错字。
  80. kbthomp1 修复了与英特尔 OSX 编译器相关的问题。
  81. Markus Werle修正了一个错别字。
  82. WebProdPP 修复了前提条件检查中的一个细微错误。
  83. Alex 注意到代码示例中的一个错误。
  84. Tom de Geus向ICC报告了一些警告,并帮助修复了它们。
  85. Perry Kundert 简化了输入流的读取。
  86. Sonu Lohani修复了一个小的编译错误。
  87. 杰米·苏厄德修复了所有MSVC警告。
  88. Nate Vargas添加了一个Doxygen标签文件。
  89. pvleuven帮助修复了ICC的警告。
  90. 帕维尔帮助修复了MSVC中的一些警告。
  91. Jamie Seward 避免了 和 中不必要的字符串副本。
    find()
    count()
  92. Mitja修复了一些错别字。
  93. Jorrit Wronski更新了Hunter软件包链接。
  94. Matthias Möller为MSVC调试视图添加了一个。
    .natvis
  95. Bogemic 修复了一些 C++17 弃用警告。
  96. Eren Okka修复了一些MSVC警告。
  97. abolz 集成了 Grisu2 算法以实现正确的浮点格式,允许更多的往返检查成功。
  98. Vadim Evard 修复了自述文件中的降价问题。
  99. 零缺陷修复了编译器警告。
  100. Kert 允许在序列化中模板化字符串类型,并添加了覆盖异常行为的可能性。
  101. mark-99帮助修复了ICC错误。
  102. Patrik Huber 修复了自述文件中的链接。
  103. johnfb 在 CBOR 的不定长度字符串的实现中发现了一个错误。
  104. Paul Fultz II 在 cget 包管理器上添加了一条注释。
  105. Wilson Lin使自述文件的集成部分更加简洁。
  106. RalfBielig 在解析器回调中检测到并修复了内存泄漏。
  107. 允许Agrianius将JSON转储到替代字符串类型。
  108. Kevin Tonon过度使用了CMake中的C++11编译器检查。
  109. Axel Huebl 简化了 CMake 检查,并添加了对 Spack 包管理器的支持。
  110. 卡洛斯·奥瑞安(Carlos O'Ryan)修正了一个错别字。
  111. James Upjohn 在编译器部分修复了一个版本号。
  112. Chuck Atkins 根据 CMake 打包指南调整了 CMake 文件,并为 CMake 集成提供了文档。
  113. Jan Schöppach修正了一个错别字。
  114. martin-mfg修复了一个错别字。
  115. Matthias Möller 从 中删除了依赖项。
    std::stringstream
  116. agrianius添加了代码以使用替代字符串实现。
  117. Daniel599 允许在该函数中使用更多算法。
    items()
  118. Julius Rakow修复了介子包含目录并修复了 cppreference.com 的链接。
  119. Sonu Lohani 在调试模式下修复了使用 MSVC 2015 的编译。
  120. grembo 修复了测试套件并重新启用了多个测试用例。
  121. Hyeon Kim 引入了宏来控制库内的异常处理。
    JSON_INTERNAL_CATCH
  122. thyu 修复了编译器警告。
  123. David Guthrie 在 Clang 3.4.2 中修复了一个微妙的编译错误。
  124. 丹尼斯·费舍尔允许在不安装库的情况下呼叫。
    find_package
  125. Hyeon Kim 修复了双重宏定义的问题。
  126. Ben Berman使一些错误消息更容易理解。
  127. zakalibit 修复了英特尔C++编译器的编译问题。
  128. 曼德雷尔修复了一个编译问题。
  129. Kostiantyn Ponomarenko 将版本和许可证信息添加到 Meson 构建文件中。
  130. Henry Schreiner增加了对GCC 4.8的支持。
  131. knilche 确保测试套件在错误的目录中运行时不会停止。
  132. Antonio Borondo修复了MSVC 2017警告。
  133. Dan Gendreau 实现了宏来快速定义枚举/JSON 映射。
    NLOHMANN_JSON_SERIALIZE_ENUM
  134. efp 添加了行和列信息以分析错误。
  135. Julian-Becker增加了BSON支持。
  136. Pratik Chowdhury 添加了对结构化绑定的支持。
  137. David Avedissian增加了对Clang 5.0.1(PS4版本)的支持。
  138. Jonathan Dumaresq 实现了一个输入适配器来读取 。
    FILE*
  139. kjpus 修复了文档中的链接。
  140. Manvendra Singh修复了文档中的拼写错误。
  141. Ziggurat29 修复了 MSVC 警告。
  142. Sylvain Corlay添加了代码以避免MSVC出现问题。
  143. mefyl修复了从输入流解析JSON时的错误。
  144. Millian Poquet允许通过Meson安装库。
  145. Michael Behrns-Miller 发现了缺少命名空间的问题。
  146. Nasztanovics Ferenc 修复了 libc 2.12 的编译问题。
  147. 安德烈亚斯·施瓦布修复了字节序转换。
  148. Mark-Dunning 修复了 MSVC 中的警告。
  149. Gareth Sylvester-Bradley为JSON Pointers添加了内容。
    operator/
  150. 约翰-马克注意到缺少一个标题。
  151. Vitaly Zaitsev 使用 GCC 9.0 修复了编译。
  152. Laurent Stacul 使用 GCC 9.0 修复编译。
  153. Ivor Wanders 帮助将 CMake 要求降低到 3.1 版。
  154. njlr更新了Buckaroo指令。
  155. Lion 修复了 CentOS 上 GCC 7 的编译问题。
  156. Isaac Nickaein 改进了整数序列化性能并实现了该函数。
    contains()
  157. 逾期禁止显示无法修复的警告。
  158. 埃尔维斯·奥里克改进了介子支持。
  159. Matěj Plch 修复了自述文件中的示例。
  160. 马克·贝克威斯修正了一个错别字。
  161. scinart 修复了序列化程序中的错误。
  162. Patrick Boettcher 实现了 JSON 指针。
    push_back()
    pop_back()
  163. Bruno Oliveira增加了对Conda的支持。
  164. Michele Caini 修复了自述文件中的链接。
  165. Hani 记录了如何使用 NuGet 安装库。
  166. 马克·贝克威斯修正了一个错别字。
  167. Yann-Morin-1998 帮助将 CMake 要求降低到 3.1 版。
  168. Konstantin Podsvirov维护了一个MSYS2软件发行版的软件包。
  169. remyabel将GNUInstallDirs添加到CMake文件中。
  170. 泰勒霍华德修复了一个单元测试。
  171. Gabe Ron实现了该方法。
    to_string
  172. 瓦塔尔·M·岩崎修复了一个叮当警告。
  173. Viktor Kirilov将单元测试从Catch切换到doctest
  174. 俊成E修正了一个错别字。
  175. tete17 修复了函数中的一个错误。
    contains
  176. Xav83 修复了一些 cppcheck 警告。
  177. 0xflotus修复了一些错别字。
  178. 克里斯蒂安·德内克(Christian Deneke)添加了 的 const 版本。
    json_pointer::back
  179. Julien Hamaide 使该函数适用于自定义字符串类型。
    items()
  180. Evan Nemerson 更新修复了 Hedley 中的一个错误,并相应地更新了这个库。
  181. Florian Pigorsch修复了很多错别字。
  182. 卡米尔·贝盖修复了从 和 到 的转换中的问题。
    std::pair
    std::tuple
    json
  183. Anthony VH 修复了枚举反序列化中的编译错误。
  184. Yuriy Vountesmery注意到预处理器检查中有一个微妙的错误。
  185. 陈修复了图书馆中的许多问题。
  186. Antony Kellermann 为 GCC 10.1 添加了一个 CI 步骤。
  187. 亚历克斯修复了 MSVC 警告。
  188. Rainer提出了对CBOR浮点序列化的改进。
  189. Francois Chabot对输入适配器进行了性能改进。
  190. Arthur Sonzogni 记录了如何通过 包含库。
    FetchContent
  191. Rimas Misevičius修复了一条错误消息。
  192. 亚历山大·米亚斯尼科夫修复了自述文件中的一些示例和链接。
  193. Hubert Chathi 使 CMake 的版本配置文件架构独立。
  194. OmnipotentEntity 实现了 CBOR、MessagePack、BSON 和 UBJSON 的二进制值。
  195. ArtemSarmini修复了GCC 10的编译问题并修复了一个泄漏。
  196. Evgenii Sopov将库集成到wsjcpp包管理器中。
  197. Sergey Linev 修复了编译器警告。
  198. 米格尔·马加良斯(Miguel Magalhães)在版权中确定了年份。
  199. Gareth Sylvester-Bradley修复了MSVC的编译问题。
  200. Alexander “weej” Jones 在自述文件中修复了一个示例。
  201. Antoine Cœur 修复了文档中的一些拼写错误。
  202. jothepro更新了Hunter软件包的链接。
  203. 戴夫·李修复了自述文件中的链接。
  204. Joël Lamotte 添加了使用 Build2 包管理器的说明。
  205. Paul Jurczak 修复了自述文件中的一个例子。
  206. Sonu Lohani修复了一个警告。
  207. 卡洛斯·戈麦斯·马蒂尼奥更新了柯南包源。
  208. Konstantin Podsvirov修复了MSYS2软件包文档。
  209. Tridacnid改进了CMake测试。
  210. Michael 修复了 MSVC 警告。
  211. 昆汀·巴巴拉特(Quentin Barbarat)在文档中修复了一个示例。
  212. XyFreak修复了编译器警告。
  213. TotalCaesar659 修复了自述文件中的链接。
  214. Tanuj Garg改进了UBSAN输入的模糊覆盖率。
  215. AODQ 修复了编译器警告。
  216. jwittbrodt make inline.
    NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
  217. pfeatherstone改进了/宏的参数上限。
    NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
    NLOHMANN_DEFINE_TYPE_INTRUSIVE
  218. Jan Procházka 修复了 CBOR 解析器中二进制和字符串值的错误。
  219. T0b1-iOS 修复了新哈希实现中的一个错误。
  220. Matthew Bauer 调整了 CBOR 编写器,为二进制子类型创建标签。
  221. gatopeich 为 实现了一个有序的映射容器。
    nlohmann::ordered_json
  222. Érico Nogueira Rolim 添加了对 pkg-config 的支持。
  223. KonanM提出了/宏的实现。
    NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
    NLOHMANN_DEFINE_TYPE_INTRUSIVE
  224. 纪尧姆·拉西科特(Guillaume Racicot)实施了支持并允许C++20支持。
    string_view
  225. Alex Reinking 改进了 CMake 对 的支持。
    FetchContent
  226. Hannes Domani提供了一台漂亮的GDB打印机。
  227. Lars Wirzenius查看了自述文件。
  228. 俊杰修复了 CMake 脚本中的编译器路径。
  229. Ronak Buch修复了文档中的拼写错误。
  230. 亚历山大·卡尔任科夫修复了一个移动构造函数,特拉维斯构建了。
  231. 莱昂纳多·利马(Leonardo Lima)增加了CPM。Cmake 支持。
  232. 约瑟夫·布莱克曼(Joseph Blackman)修复了一个警告。
  233. 雅罗斯拉夫更新了文档测试并实现了单元测试。
  234. Martin Stump 修复了 CMake 文件中的一个错误。
  235. Jaakko Moisio修复了输入适配器中的一个错误。
  236. bl-ue 修复了自述文件中的一些 Markdown 问题。
  237. William A. Wieselquist修复了自述文件中的一个例子。
  238. 阿巴斯瓦西姆修复了自述文件中的一个例子。
  239. 雷米·杰特(Remy Jette)修复了一个警告。
  240. 弗雷泽修复了文档。
  241. Ben Beasley 更新了 doctest。
  242. Doron Behar fixed pkg-config.pc.
  243. 拉杜蒂奥修复了一个警告。
  244. David Pfahler 添加了在没有 I/O 支持的情况下编译库的可能性。
  245. Morten Fyhn Amundsen修正了一个错字。
  246. JPL-MAC 允许将库视为 CMake 中的系统标头。
  247. Jason Dsouza 修复了 CMake 文件的缩进。
  248. Offa 在文档中添加了指向柯南中心的链接。
  249. TotalCaesar659更新了文档中的链接以使用HTTPS。
  250. Rafail Giavrimis 修复了 Google Benchmark 默认分支。
  251. Louis Dionne 修复了一个转换运算符。
  252. justotheranonymoususer使自述文件中的示例更加一致。
  253. 芬克曼压制了一些警告。
    -Wfloat-equal
  254. 费里·休伯茨修复了警告。
    -Wswitch-enum
  255. Arseniy Terekhin使GDB漂亮的打印机能够抵御未设置的变量名称。
  256. Amir Masoud Abdol更新了Homebrew命令,因为nlohmann / json现在在Homebrew-core中。
  257. 哈洛特修复了一些.
    -Wextra-semi-stmt warnings
  258. 乔瓦尼·塞雷塔尼修复了警告。
    -Wunused
    JSON_DIAGNOSTICS
  259. Bogdan Popescu 为离线文档查看者托管文档集
  260. Carl Smedstad 修复了使用 .
    JSON_DIAGNOSTICS
  261. miikka75 提供了一个重要的修复程序,用于使用 Clang 9 编译 C++17 代码。
  262. Maarten Becker修复了阴影变量的警告。
  263. Cristi Vîjdea 修复了文档中的拼写错误。
    operator[]
  264. Alex Beregszaszi修复了评论中的拼写错误。
  265. Dirk Stolle修复了文档中的拼写错误。
  266. Daniel Albuschat 更正了文档中的参数名称。
    parse
  267. 门迪拉塔王子修复了常见问题解答的链接。
  268. Florian Albrechtskirchinger实现了对对象键的支持,并进行了数十项其他改进。
    std::string_view
  269. Fianqian Fang实现了二进制JData(BJData)格式。
  270. pketelsen 添加了宏和 .
    NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT
    NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT
  271. DarkZeros调整了代码,以免与Arduino定义冲突。
  272. flagarde修复了MSVC的输出。
    meta()
  273. 乔瓦尼·塞雷塔尼修复了 .
    std::filesystem
  274. 迪米特里斯·阿波斯托鲁修正了一个错别字。
  275. 费里·休伯茨修正了一个错别字。
  276. Michael Nosthoff修正了一个错别字。
  277. 李贞勋修正了一个错别字。
  278. 法鲁克·修复了引文。CFF 文件。
  279. Andrea Cocito在文档中添加了有关宏用法的说明。
  280. Krzysiek Karbowiak 重构了要使用的测试。
    CHECK_THROWS_WITH_AS
  281. 张朝琪修正了一个错别字。
  282. ivanovmp 修复了一个空格错误。
  283. KsaNL 修复了包含 .
    <windows.h>
  284. 安德里亚·帕帕科达(Andrea Pappacoda)移动并将文件移至目录。
    .pc
    .cmake
    share
  285. Wolf Vollprecht添加了该功能。
    patch_inplace
  286. Jake Zimmerman 强调了自述文件中的常见使用模式。
  287. NN 将 Visual Studio 输出目录添加到 。
    .gitignore
  288. Romain Reignier改进了矢量输出适配器的性能。
  289. 迈克修复了 .
    std::iterator_traits
  290. Richard Hozák 添加了宏来禁用默认枚举转换。
    JSON_NO_ENUM
  291. Vakokako 在使用 C++20 编译时修复了测试。
  292. Alexander “weej” Jones 在自述文件中修复了一个示例。
  293. Eli Schwartz在存档中添加了更多文件。
    include.zip
  294. Kevin Lu 修复了存在具有某些名称的 typedef 时的编译问题。
  295. 特雷弗·希基(Trevor Hickey)改进了示例的描述。
  296. Jef LeCompte 更新了自述文件中的年份。
  297. 亚历山大·哈梅兹(Alexandre Hamez)修复了一个警告。
  298. Maninderpal Badhan修正了一个错别字。
  299. kevin-- 在自述文件中的示例中添加了一个注释。
  300. 修正了一个错别字。
  301. 格雷戈里奥·利滕斯坦修复了Clang检测。
  302. 安德烈亚斯·斯马斯(Andreas Smas)增加了一个Doozer徽章。
  303. WanCW用Clang修复了字符串转换。
  304. 昭华西石修复了一个Doxygen错误。
  305. emvivre 从 CMake 中删除了一个无效的参数。
  306. Tobias Hermann 修复了自述文件中的链接。
  307. 迈克尔修复了一个警告。
  308. Ryan Mulder添加到该功能中。
    ensure_ascii
    dump
  309. Muri Nicanor修复了Makefile中的发现。
    sed
  310. David Avedissian实现了SFINAE友好。
    iterator_traits
  311. AQNOUCH Mohammed修复了自述文件中的拼写错误。
  312. Gareth Sylvester-Bradley添加并构建了JSON指针。
    operator/=
    operator/
  313. Michael Macnair增加了对afl-fuzz测试的支持。
  314. Berkus Decker修复了自述文件中的一个拼写错误。
  315. Illia Polishchuk改进了CMake测试。
  316. Ikko Ashimine修正了一个错别字。

非常感谢你的帮助!如果我忘记了某人,请告诉我

使用的第三方工具

库本身由一个根据 MIT 许可证许可的头文件组成。但是,它是构建,测试,记录的,以及不使用大量第三方工具和服务的内容。多谢!

使用 JSON 进行现代C++的项目

该库目前用于Apple macOS Sierra-Monterey和iOS 10-15。我不确定他们使用该库的目的是什么,但我很高兴它在这么多设备上运行。

笔记

字符编码

该库支持 Unicode 输入,如下所示:

  • 仅支持 UTF-8 编码输入,这是根据 RFC 8259 对 JSON 的默认编码。
  • std::u16string
    并且可以解析,分别假设 UTF-16 和 UTF-32 编码。从文件或其他输入容器读取时不支持这些编码。
    std::u32string
  • 不支持其他编码(如 Latin-1 或 ISO 8859-1),并且会产生分析或序列化错误。
  • Unicode 非字符不会被库替换。
  • 无效的代理项(例如,不完整的对,如 )将产生解析错误。
    \uDEAD
  • 存储在库中的字符串采用 UTF-8 编码。使用默认字符串类型 () 时,请注意其长度/大小函数返回存储的字节数,而不是字符或字形的数量。
    std::string
  • 当你在库中存储具有不同编码的字符串时,调用 dump() 可能会引发异常,除非 或 用作错误处理程序。
    json::error_handler_t::replace
    json::error_handler_t::ignore
  • 要存储宽字符串(例如,),你需要将它们转换为之前编码的 UTF-8,请参阅示例
    std::wstring
    std::string

JSON 中的注释

默认情况下,此库不支持注释。它这样做有三个原因:

  1. 注释不是 JSON 规范的一部分。你可能会争辩说,在 JavaScript 中是允许的,但 JSON 不是 JavaScript。

    //
    /* */

  2. 这不是一个疏忽:道格拉斯·克罗克福德(Douglas Crockford)在2012年5月写道

    我从JSON中删除了注释,因为我看到人们正在使用它们来保存解析指令,这种做法会破坏互操作性。我知道缺乏评论会让一些人感到难过,但不应该。

    假设你使用 JSON 来保存要注释的配置文件。继续并插入你喜欢的所有评论。然后通过 JSMin 通过管道将其传递给你的 JSON 解析器。

  3. 如果某些库会添加注释支持,而其他库则不会,那么互操作性是危险的。请查看鲁棒性原则的有害后果

但是,你可以在函数中将 set 参数传递给 true 以忽略或注释。然后,注释将被视为空格。

ignore_comments
parse
//
/* */

对象键的顺序

默认情况下,库不保留对象元素的插入顺序。这是符合标准的,因为 JSON 标准将对象定义为“零个或多个名称/值对的无序集合”。

如果你确实想保留广告顺序,可以尝试使用 nlohmann::ordered_json 类型。或者,你可以使用更复杂的有序映射,如 tsl::ordered_map集成)或 nlohmann::fifo_map集成)。

内存释放

我们与Valgrind和地址清理器(ASAN)进行了检查,没有内存泄漏。

如果发现带有此库的解析程序不释放内存,请考虑以下情况,它可能与此库无关。

你的程序是使用 glibc 编译的。glibc 使用一个可调阈值来决定是实际将内存返回到系统还是缓存内存以供以后重用。如果你在程序中进行了大量小分配,并且这些小分配不是连续块并且可能低于阈值,那么它们将不会返回到操作系统。这是一个相关的问题#1924

进一步说明

  • 该代码包含许多调试断言,可以通过定义预处理器宏来关闭这些言,请参阅断言的文档。特别是,note operator[] 实现了对 const 对象的未经检查的访问:如果给定的键不存在,则行为是未定义的(想想取消引用的空指针),如果断言打开,则会导致断言失败。如果不确定对象中的元素是否存在,请将 checked 访问与 at() 函数一起使用。此外,还可以定义替换对 的调用。
    NDEBUG
    JSON_ASSERT(x)
    assert(x)
  • 由于 JSON 规范中未定义确切的数字类型,因此此库会尝试自动选择最适合C++数字类型。因此,如果浮点异常已在调用代码中被屏蔽,则该类型可用于存储数字,这些数字在某些极少数情况下可能会产生浮点异常。这些异常不是由库引起的,需要在调用代码中修复,例如在调用库函数之前重新屏蔽异常。
    double
  • 可以在没有运行时类型标识功能的情况下编译代码C++;也就是说,你可以使用编译器标志。
    -fno-rtti
  • 例外在库中被广泛使用。但是,可以使用编译器标志或通过定义符号来关闭它们。在这种情况下,异常将替换为调用。你可以通过定义 (覆盖)、(覆盖 ) 和 (覆盖) 来进一步控制此行为。请注意,应该将当前范围(例如,通过抛出或中止)保留为继续,因为它可能会产生未定义的行为。请注意,如果禁用异常,则解释性 what() 异常字符串不适用于 MSVC,请参阅 #2824
    -fno-exceptions
    JSON_NOEXCEPTION
    abort()
    JSON_THROW_USER
    throw
    JSON_TRY_USER
    try
    JSON_CATCH_USER
    catch
    JSON_THROW_USER

执行单元测试

要编译和运行测试,你需要执行

$ mkdir build
$ cd build
$ cmake .. -DJSON_BuildTests=On
$ cmake --build .
$ ctest --output-on-failure

请注意,在此阶段,将从外部存储库下载多个 JSON 测试文件。如果策略禁止在测试期间下载项目,则可以自行下载文件,并将包含测试文件的目录传递给 CMake。然后,不需要互联网连接。有关详细信息,请参阅问题 #2189

ctest
-DJSON_TestDataDirectory=path

如果未找到测试套件,则多个测试套件将失败,如下所示:

===============================================================================
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 <https://github.com/nlohmann/json#execute-unit-tests> for more information.

===============================================================================

如果你下载了库而不是通过 Git 签出代码,则测试将失败。请执行以跳过这些测试。有关详细信息,请参阅问题 #2189

cmake_fetch_content_configure
ctest -LE git_required

一些测试会更改已安装的文件,从而使整个过程不可重现。请执行以跳过这些测试。有关详细信息,请参阅问题 #2324

ctest -LE not_reproducible

请注意,你需要调用以排除这两个标签。有关详细信息,请参阅问题 #2596

cmake -LE "not_reproducible|git_required"

由于英特尔编译器默认使用不安全的浮点优化,因此单元测试可能会失败。然后使用标志 /fp:precision