-
Notifications
You must be signed in to change notification settings - Fork 72
Custom conversion (zh)
Nomango edited this page Jan 5, 2023
·
4 revisions
configor 提供了 CONFIGOR_BIND
宏,可以用一行代码快速完成自定义类型绑定:
struct User
{
int user_id;
std::string user_name;
CONFIGOR_BIND(
json::value, User, // 将 User 类绑定到 json
REQUIRED(user_id), // user_id 字段必填,空值会引发异常
OPTIONAL(user_name) // user_name 字段非必填,空值会被忽略
);
};
对私有成员变量同样适用
class User
{
private:
int user_id;
std::string user_name;
public:
// 绑定私有字段
CONFIGOR_BIND(json::value, User, REQUIRED(user_id), OPTIONAL(user_name));
};
允许指定与 C++ 字段名不同的 JSON 字段名
class User
{
private:
int user_id_;
std::string user_name_;
public:
// 为 JSON 指定不同的名称,使 User 可以接受如 {"id": 1, "name": "John"} 这样的 JSON 内容
CONFIGOR_BIND(json::value, User, REQUIRED(user_id_, "id"), OPTIONAL(user_name_, "name"));
};
绑定宽字符类型的字段时,必须指定 L 开头的字段名
class User
{
private:
int user_id;
std::wstring user_name;
public:
// 绑定到 wjson 类型,使用 L 开头的宽字符字段名
CONFIGOR_BIND(wjson::value, User, REQUIRED(user_id, L"user_id"), OPTIONAL(user_name, L"user_name"));
};
为了方便,可以自定义一个转换宏,例如
#define WREQUIRED(field) REQUIRED(field, L ## #field)
#define WOPTIONAL(field) OPTIONAL(field, L ## #field)
class User
{
private:
int user_id;
std::wstring user_name;
public:
// 绑定到 wjson 类型,使用 WREQUIRED 和 WOPTIONAL
CONFIGOR_BIND(wjson::value, User, WREQUIRED(user_id), WOPTIONAL(user_name));
};
json::value j;
User user;
// 将 User 转换为 json
j = user;
// 将 json 转换为 User
user = (User)j;
同时会默认支持 User 的智能指针、std::vector<User>、std::map<std::string, User> 等类型的自动转换。
例如,下面的代码是正确的:
std::vector<std::shared_ptr<User>> user_list;
json::value j = user_list; // 可以正确处理复合类型的转换
对于第三方库的类型,由于无法侵入式的在其内部声明 CONFIGOR_BIND,可以通过特化实现 value_binder 类,非侵入式的绑定到 JSON。
特化实现 value_binder 的例子:
// 用户类
struct User
{
int user_id;
std::string user_name;
};
// 与 json 绑定
namespace configor
{
template <>
struct value_binder<User>
{
static void to_value(json& j, const User& v)
{
j = { { "user_id", v.user_id }, { "user_name", v.user_name } };
}
static void from_value(const json& j, User& v)
{
j["user_id"].get(v.user_id);
j["user_name"].get(v.user_name);
}
};
}
使用 json::wrap 函数可以让任意类型实现序列化与反序列化,并与输入输出流交互
std::stringstream s;
// 把 obj 序列化,并输入到 s 流中
s << json::wrap(obj);
// 从 s 流中读取,并把 obj 反序列化
s >> json::wrap(obj);