nlohmann::json库对象和json结构体转换的新方式
nlohmann::json库官方地址为:https://json.nlohmann.me/,Github源代码托管地址为:https://github.com/nlohmann/json
在nlohmann json库 3.9.0 版本之前,如果将自定义类或者结构体对象之间相关转换,需要自定义对应的to_json和from_json这两个函数。但是从3.9.0版本以后有6个宏可以替我们完成这项事情,具体可以参考官方文档:

https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive

NLOHMANN_DEFINE_TYPE_INTRUSIVE
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT
NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE
其中,前面3个宏是侵入式的,需要在类或结构体对象里面进行声明使用;
后面3个宏是非侵入式的,可以在类或结构体对象外部定义,但是需要和该类或结构体定义在同一个命名空间中。
当前实现最多支持 64 个成员变量。如果要序列化/反序列化包含超过 64 个成员变量的类型,则需要手动定义 to_json/from_json 函数。
6个宏的定义
1. NLOHMANN_DEFINE_TYPE_INTRUSIVE
cpp
/*!
@brief macro
@def NLOHMANN_DEFINE_TYPE_INTRUSIVE
@since version 3.9.0
@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/
*/
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
2. NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT
cpp
/*!
@brief macro
@def NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT
@since version 3.11.0
@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/
*/
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
3. NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE
cpp
/*!
@brief macro
@def NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE
@since version 3.11.3
@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/
*/
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
4. NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
cpp
/*!
@brief macro
@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
@since version 3.9.0
@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/
*/
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
5. NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT
cpp
/*!
@brief macro
@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT
@since version 3.11.0
@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/
*/
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
6. NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE
cpp
/*!
@brief macro
@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE
@since version 3.11.3
@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/
*/
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
侵入式代码示例
主要涉及到NLOHMANN_DEFINE_TYPE_INTRUSIVE、
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT、
NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE
这3个宏
如果您希望使用 JSON 对象进行序列化,并希望将成员变量名用作该对象的键,则可以使用这些宏来简化类型的序列化/反序列化。该宏需要在要为其编写代码的类/结构体内部定义。与 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE 不同,它可以访问私有成员。第一个参数是类/结构体的名称,其余参数均为成员名称。
-
- 反序列化时将使用
at参数,如果 JSON 对象中缺少某个键,则会抛出out_of_range.403异常。
- 反序列化时将使用
-
- 反序列化时将使用
value参数,如果 JSON 对象中缺少某个键,则会回退到成员变量相应类型的默认值。生成的from_json()函数默认会构造一个对象,并在调用value函数时使用其值作为默认值。
- 反序列化时将使用
- 3.仅定义序列化。当类型没有默认构造函数且仅需要序列化时,此宏非常有用。
默认定义
这些宏为类添加了两个友元函数,分别负责序列化和反序列化:
cpp
template<typename BasicJsonType>
friend void to_json(BasicJsonType&, const type&);
template<typename BasicJsonType>
friend void from_json(const BasicJsonType&, type&); // except (3)
1. Example (1): NLOHMANN_DEFINE_TYPE_INTRUSIVE
请看以下完整示例:
cpp
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
using namespace nlohmann::literals;
namespace ns
{
class person
{
private:
std::string name = "John Doe";
std::string address = "123 Fake St";
int age = -1;
public:
person() = default;
person(std::string name_, std::string address_, int age_)
: name(std::move(name_)), address(std::move(address_)), age(age_)
{}
NLOHMANN_DEFINE_TYPE_INTRUSIVE(person, name, address, age)
};
} // namespace ns
int main()
{
ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};
// serialization: person -> json
json j = p;
std::cout << "serialization: " << j << std::endl;
// deserialization: json -> person
json j2 = R"({"address": "742 Evergreen Terrace", "age": 40, "name": "Homer Simpson"})"_json;
auto p2 = j2.get<ns::person>();
// incomplete deserialization:
json j3 = R"({"address": "742 Evergreen Terrace", "name": "Maggie Simpson"})"_json;
try
{
auto p3 = j3.get<ns::person>();
}
catch (const json::exception& e)
{
std::cout << "deserialization failed: " << e.what() << std::endl;
}
}
输出:
bash
serialization: {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"}
deserialization failed: [json.exception.out_of_range.403] key 'age' not found
注释:
-
ns::person 是默认可构造的。这是使用该宏的必要条件。
-
ns::person 包含私有成员变量。因此,可以使用 NLOHMANN_DEFINE_TYPE_INTRUSIVE,但不能使用 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE。
-
宏 NLOHMANN_DEFINE_TYPE_INTRUSIVE 在类内部使用。
-
反序列化过程中如果缺少键"age",则会引发异常。要回退到默认值,可以使用 NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT。
该宏等效于:
cpp
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
using namespace nlohmann::literals;
namespace ns
{
class person
{
private:
std::string name = "John Doe";
std::string address = "123 Fake St";
int age = -1;
public:
person() = default;
person(std::string name_, std::string address_, int age_)
: name(std::move(name_)), address(std::move(address_)), age(age_)
{}
// NLOHMANN_DEFINE_TYPE_INTRUSIVE(person, name, address, age) 等价于下面两个友元函数 to_json 和 from_json
template<typename BasicJsonType>
friend void to_json(BasicJsonType& nlohmann_json_j, const person& nlohmann_json_t)
{
nlohmann_json_j["name"] = nlohmann_json_t.name;
nlohmann_json_j["address"] = nlohmann_json_t.address;
nlohmann_json_j["age"] = nlohmann_json_t.age;
}
template<typename BasicJsonType>
friend void from_json(const BasicJsonType& nlohmann_json_j, person& nlohmann_json_t)
{
nlohmann_json_t.name = nlohmann_json_j.at("name");
nlohmann_json_t.address = nlohmann_json_j.at("address");
nlohmann_json_t.age = nlohmann_json_j.at("age");
}
};
} // namespace ns
int main()
{
ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};
// serialization: person -> json
json j = p;
std::cout << "serialization: " << j << std::endl;
// deserialization: json -> person
json j2 = R"({"address": "742 Evergreen Terrace", "age": 40, "name": "Homer Simpson"})"_json;
auto p2 = j2.get<ns::person>();
// incomplete deserialization:
json j3 = R"({"address": "742 Evergreen Terrace", "name": "Maggie Simpson"})"_json;
try
{
auto p3 = j3.get<ns::person>();
}
catch (const json::exception& e)
{
std::cout << "deserialization failed: " << e.what() << std::endl;
}
}
2. Example (2): NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT
请看以下完整示例:
cpp
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
using namespace nlohmann::literals;
namespace ns
{
class person
{
private:
std::string name = "John Doe";
std::string address = "123 Fake St";
int age = -1;
public:
person() = default;
person(std::string name_, std::string address_, int age_)
: name(std::move(name_)), address(std::move(address_)), age(age_)
{}
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(person, name, address, age)
};
} // namespace ns
int main()
{
ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};
// serialization: person -> json
json j = p;
std::cout << "serialization: " << j << std::endl;
// deserialization: json -> person
json j2 = R"({"address": "742 Evergreen Terrace", "age": 40, "name": "Homer Simpson"})"_json;
auto p2 = j2.get<ns::person>();
// incomplete deserialization:
json j3 = R"({"address": "742 Evergreen Terrace", "name": "Maggie Simpson"})"_json;
auto p3 = j3.get<ns::person>();
std::cout << "roundtrip: " << json(p3) << std::endl;
}
输出:
cpp
serialization: {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"}
roundtrip: {"address":"742 Evergreen Terrace","age":-1,"name":"Maggie Simpson"}
注释:
-
ns::person 是默认可构造的。这是使用该宏的必要条件。
-
ns::person 包含私有成员变量。因此,NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT 宏适用,但 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT 宏不适用。
-
宏 NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT 在类内部使用。
-
反序列化过程中缺少键"age"不会引发异常。而是使用默认值 -1。
该宏等效于:
cpp
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
using namespace nlohmann::literals;
namespace ns
{
class person
{
private:
std::string name = "John Doe";
std::string address = "123 Fake St";
int age = -1;
public:
person() = default;
person(std::string name_, std::string address_, int age_)
: name(std::move(name_)), address(std::move(address_)), age(age_)
{}
// NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(person, name, address, age) 等效于下面2个友元函数 to_json 和 from_json
template<typename BasicJsonType>
friend void to_json(BasicJsonType& nlohmann_json_j, const person& nlohmann_json_t)
{
nlohmann_json_j["name"] = nlohmann_json_t.name;
nlohmann_json_j["address"] = nlohmann_json_t.address;
nlohmann_json_j["age"] = nlohmann_json_t.age;
}
template<typename BasicJsonType>
friend void from_json(const BasicJsonType& nlohmann_json_j, person& nlohmann_json_t)
{
person nlohmann_json_default_obj;
nlohmann_json_t.name = nlohmann_json_j.value("name", nlohmann_json_default_obj.name);
nlohmann_json_t.address = nlohmann_json_j.value("address", nlohmann_json_default_obj.address);
nlohmann_json_t.age = nlohmann_json_j.value("age", nlohmann_json_default_obj.age);
}
};
} // namespace ns
int main()
{
ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};
// serialization: person -> json
json j = p;
std::cout << "serialization: " << j << std::endl;
// deserialization: json -> person
json j2 = R"({"address": "742 Evergreen Terrace", "age": 40, "name": "Homer Simpson"})"_json;
auto p2 = j2.get<ns::person>();
// incomplete deserialization:
json j3 = R"({"address": "742 Evergreen Terrace", "name": "Maggie Simpson"})"_json;
auto p3 = j3.get<ns::person>();
std::cout << "roundtrip: " << json(p3) << std::endl;
}
请注意,from_json 中使用了默认初始化的 person 对象来填充缺失值。
3. Example (3): NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE
请看以下完整示例:
cpp
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
using namespace nlohmann::literals;
namespace ns
{
class person
{
private:
std::string name = "John Doe";
std::string address = "123 Fake St";
int age = -1;
public:
// No default constructor
person(std::string name_, std::string address_, int age_)
: name(std::move(name_)), address(std::move(address_)), age(age_)
{}
NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(person, name, address, age)
};
} // namespace ns
int main()
{
ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};
// serialization: person -> json
json j = p;
std::cout << "serialization: " << j << std::endl;
}
输出:
bash
serialization: {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"}
注释:
-
ns::person 是不可默认构造的。因此,可以使用此宏代替 NLOHMANN_DEFINE_TYPE_INTRUSIVE 和 NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT。
-
ns::person 具有私有成员变量。因此,可以使用 NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE,但不能使用 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE。
-
宏 NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE 在类内部使用。
该宏等效于:
cpp
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
using namespace nlohmann::literals;
namespace ns
{
class person
{
private:
std::string name = "John Doe";
std::string address = "123 Fake St";
int age = -1;
public:
// No default constructor
person(std::string name_, std::string address_, int age_)
: name(std::move(name_)), address(std::move(address_)), age(age_)
{}
template<typename BasicJsonType>
friend void to_json(BasicJsonType& nlohmann_json_j, const person& nlohmann_json_t)
{
nlohmann_json_j["name"] = nlohmann_json_t.name;
nlohmann_json_j["address"] = nlohmann_json_t.address;
nlohmann_json_j["age"] = nlohmann_json_t.age;
}
};
} // namespace ns
int main()
{
ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};
// serialization: person -> json
json j = p;
std::cout << "serialization: " << j << std::endl;
}
非侵入式代码示例
主要涉及到NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE、NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT和NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE
这3个宏
如果您希望使用 JSON 对象进行序列化,并希望将成员变量名用作该对象的键,则可以使用这些宏来简化类型的序列化/反序列化。该宏需要在要为其编写代码的类/结构体内部定义。与 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE 不同,它可以访问私有成员。第一个参数是类/结构体的名称,其余参数均为成员名称。
-
1.反序列化时将使用
at参数,如果 JSON 对象中缺少某个键,则会抛出out_of_range.403异常。 -
2.反序列化时将使用
value参数,如果 JSON 对象中缺少某个键,则会回退到成员变量相应类型的默认值。生成的from_json()函数默认会构造一个对象,并在调用value函数时使用其值作为默认值。 -
3.仅定义序列化。当类型没有默认构造函数且仅需要序列化时,此宏非常有用。
1. Example (1): NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
请看以下完整示例:
cpp
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
using namespace nlohmann::literals;
namespace ns
{
struct person
{
std::string name;
std::string address;
int age;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age)
} // namespace ns
int main()
{
ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};
// serialization: person -> json
json j = p;
std::cout << "serialization: " << j << std::endl;
// deserialization: json -> person
json j2 = R"({"address": "742 Evergreen Terrace", "age": 40, "name": "Homer Simpson"})"_json;
auto p2 = j2.get<ns::person>();
// incomplete deserialization:
json j3 = R"({"address": "742 Evergreen Terrace", "name": "Maggie Simpson"})"_json;
try
{
auto p3 = j3.get<ns::person>();
}
catch (const json::exception& e)
{
std::cout << "deserialization failed: " << e.what() << std::endl;
}
}
输出:
bash
serialization: {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"}
deserialization failed: [json.exception.out_of_range.403] key 'age' not found
注释
-
ns::person 是默认可构造的。这是使用该宏的必要条件。
-
ns::person 只有公共成员变量。因此,可以使用 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE。
-
宏 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE 在类外部、命名空间 ns 内使用。
-
反序列化过程中如果缺少键"age",则会引发异常。要回退到默认值,可以使用 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT。
该宏等效于:
cpp
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
using namespace nlohmann::literals;
namespace ns
{
struct person
{
std::string name;
std::string address;
int age;
};
// NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age) 宏
// 展开后等价于下面to_json 和 from_json 这两个模版函数
template<typename BasicJsonType>
void to_json(BasicJsonType& nlohmann_json_j, const person& nlohmann_json_t)
{
nlohmann_json_j["name"] = nlohmann_json_t.name;
nlohmann_json_j["address"] = nlohmann_json_t.address;
nlohmann_json_j["age"] = nlohmann_json_t.age;
}
template<typename BasicJsonType>
void from_json(const BasicJsonType& nlohmann_json_j, person& nlohmann_json_t)
{
nlohmann_json_t.name = nlohmann_json_j.at("name");
nlohmann_json_t.address = nlohmann_json_j.at("address");
nlohmann_json_t.age = nlohmann_json_j.at("age");
}
} // namespace ns
int main()
{
ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};
// serialization: person -> json
json j = p;
std::cout << "serialization: " << j << std::endl;
// deserialization: json -> person
json j2 = R"({"address": "742 Evergreen Terrace", "age": 40, "name": "Homer Simpson"})"_json;
auto p2 = j2.get<ns::person>();
// incomplete deserialization:
json j3 = R"({"address": "742 Evergreen Terrace", "name": "Maggie Simpson"})"_json;
try
{
auto p3 = j3.get<ns::person>();
}
catch (const json::exception& e)
{
std::cout << "deserialization failed: " << e.what() << std::endl;
}
}
Example (2): NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT
请看以下完整示例:
cpp
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
using namespace nlohmann::literals;
namespace ns
{
struct person
{
std::string name = "John Doe";
std::string address = "123 Fake St";
int age = -1;
person() = default;
person(std::string name_, std::string address_, int age_)
: name(std::move(name_)), address(std::move(address_)), age(age_)
{}
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(person, name, address, age)
} // namespace ns
int main()
{
ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};
// serialization: person -> json
json j = p;
std::cout << "serialization: " << j << std::endl;
// deserialization: json -> person
json j2 = R"({"address": "742 Evergreen Terrace", "age": 40, "name": "Homer Simpson"})"_json;
auto p2 = j2.get<ns::person>();
// incomplete deserialization:
json j3 = R"({"address": "742 Evergreen Terrace", "name": "Maggie Simpson"})"_json;
auto p3 = j3.get<ns::person>();
std::cout << "roundtrip: " << json(p3) << std::endl;
}
输出:
bash
serialization: {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"}
roundtrip: {"address":"742 Evergreen Terrace","age":-1,"name":"Maggie Simpson"}
注释:
-
ns::person是默认可构造的。这是使用该宏的必要条件。 -
ns::person只有公共成员变量。因此,宏NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT适用。 -
宏
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT在类外部、命名空间ns内使用。 -
反序列化过程中缺少键"age"不会引发异常。而是使用默认值 -1。
该宏等效于:
cpp
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
using namespace nlohmann::literals;
namespace ns
{
struct person
{
std::string name = "John Doe";
std::string address = "123 Fake St";
int age = -1;
person() = default;
person(std::string name_, std::string address_, int age_)
: name(std::move(name_)), address(std::move(address_)), age(age_)
{}
};
// NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(person, name, address, age) 宏
// 展开后等价于下面to_json 和 from_json 这两个模版函数
template<typename BasicJsonType>
void to_json(BasicJsonType& nlohmann_json_j, const person& nlohmann_json_t)
{
nlohmann_json_j["name"] = nlohmann_json_t.name;
nlohmann_json_j["address"] = nlohmann_json_t.address;
nlohmann_json_j["age"] = nlohmann_json_t.age;
}
template<typename BasicJsonType>
void from_json(const BasicJsonType& nlohmann_json_j, person& nlohmann_json_t)
{
person nlohmann_json_default_obj;
nlohmann_json_t.name = nlohmann_json_j.value("name", nlohmann_json_default_obj.name);
nlohmann_json_t.address = nlohmann_json_j.value("address", nlohmann_json_default_obj.address);
nlohmann_json_t.age = nlohmann_json_j.value("age", nlohmann_json_default_obj.age);
}
} // namespace ns
int main()
{
ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};
// serialization: person -> json
json j = p;
std::cout << "serialization: " << j << std::endl;
// deserialization: json -> person
json j2 = R"({"address": "742 Evergreen Terrace", "age": 40, "name": "Homer Simpson"})"_json;
auto p2 = j2.get<ns::person>();
// incomplete deserialization:
json j3 = R"({"address": "742 Evergreen Terrace", "name": "Maggie Simpson"})"_json;
auto p3 = j3.get<ns::person>();
std::cout << "roundtrip: " << json(p3) << std::endl;
}
请注意,from_json 中使用了默认初始化的 person 对象来填充缺失值。
Example (3): NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE
请看以下完整示例:
cpp
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
using namespace nlohmann::literals;
namespace ns
{
struct person
{
std::string name;
std::string address;
int age;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(person, name, address, age)
} // namespace ns
int main()
{
ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};
// serialization: person -> json
json j = p;
std::cout << "serialization: " << j << std::endl;
}
输出:
cpp
serialization: {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"}
注释:
-
ns::person 是不可默认构造的。因此,可以使用此宏代替 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE 和 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT。
-
ns::person 只有公共成员变量。因此,可以使用 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE。
该宏等效于:
cpp
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
using namespace nlohmann::literals;
namespace ns
{
struct person
{
std::string name;
std::string address;
int age;
};
// NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(person, name, address, age) 等价于下面 to_json 这个模版函数
template<typename BasicJsonType>
void to_json(BasicJsonType& nlohmann_json_j, const person& nlohmann_json_t)
{
nlohmann_json_j["name"] = nlohmann_json_t.name;
nlohmann_json_j["address"] = nlohmann_json_t.address;
nlohmann_json_j["age"] = nlohmann_json_t.age;
}
} // namespace ns
int main()
{
ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};
// serialization: person -> json
json j = p;
std::cout << "serialization: " << j << std::endl;
}