c++ struct 使用boost::pfr json序列化、反序列化
#include <iostream>
#include <string>
#include <string_view>
#include <boost/pfr.hpp>
#include <nlohmann/json.hpp>
struct UV
{
int u;
int v;
};
struct XYZ {
int x;
int y;
int z;
UV uv;
};
// 定义一个简单的结构体用于演示
struct Person {
std::string name;
int age;
double height;
XYZ pos = { 1,2,3 };
std::vector<std::string> dd = { "10,11","ddd"};
};
// 使用 SFINAE 约束的通用打印函数
template <typename T>
requires std::is_aggregate_v<T>
void print_struct_members(const T& obj) {
std::cout << "{" << std::endl;
boost::pfr::for_each_field_with_name(obj, [&](std::string_view name, const auto& field) {
//std::remove_cvref_t去除 const等引用返回基础类型 避免 std::decay_t 数组指针退化
if constexpr (std::is_aggregate_v<std::remove_cvref_t<decltype(field)>>)
{
std::cout << "\"" << name << "\"" << ":" << std::endl;
print_struct_members(field);
}
else
{
std::cout << "\"" << name << "\"" << ": " << field << std::endl;
}
});
std::cout << "}" << std::endl;
}
// Concept for types that nlohmann::json can serialize/deserialize directly
template<typename T>
concept JsonSerializable = requires(T t, nlohmann::json j) {
{ j = t } -> std::same_as<nlohmann::json&>;
{ j.get<T>() } -> std::same_as<T>;
};
// Concept for std::vector
template<typename T>
concept IsVector = std::same_as<T, std::vector<typename T::value_type>>;
// Concept for std::array
template<typename T>
concept IsArray = std::same_as<T, std::array<typename T::value_type, T::size()>>;
// Concept for reflectable structs
template<typename S>
concept IsReflectable = requires {
requires std::is_aggregate_v<S>;
requires checkStructTypes<S>(std::make_index_sequence<boost::pfr::tuple_size_v<S>>{});
requires boost::pfr::tuple_size_v<S> > 0; // Ensure struct is not empty
};
// Concept for allowed field types
template<typename T>
concept FieldValueType = JsonSerializable<T> ||
IsReflectable<T> || (IsVector<T> && IsReflectable<typename T::value_type>) || (IsArray<T> && IsReflectable<typename T::value_type>);
// Helper to check if all fields of a struct satisfy FieldValueType
template<typename S, std::size_t... Is>
consteval bool checkStructTypes(std::index_sequence<Is...>) noexcept {
return (FieldValueType<std::remove_cvref_t<decltype(boost::pfr::get<Is>(std::declval<S&>()))>> && ...);
}
// Static assert to improve error messages
template<typename T>
requires IsReflectable<T>
struct JsonSer {
static_assert(IsReflectable<T>, "Type T must be an aggregate struct with fields satisfying FieldValueType");
public:
using JsonType = nlohmann::json;
// Serialization: Convert struct to JSON
static JsonType toJson(T const& object) {
JsonType json;
boost::pfr::for_each_field_with_name(object, [&json](std::string_view const name, auto const& field) {
try {
using ChildType = std::remove_cvref_t<decltype(field)>;
if constexpr (IsReflectable<ChildType>) {
json[name] = JsonSer<ChildType>::toJson(field);
}
else if constexpr (IsVector<ChildType> || IsArray<ChildType>) {
JsonType array = JsonType::array();
for (const auto& element : field) {
if constexpr (IsReflectable<typename ChildType::value_type>) {
array.push_back(JsonSer<typename ChildType::value_type>::toJson(element));
}
else {
array.push_back(element);
}
}
json[name] = array;
}
else {
static_assert(JsonSerializable<ChildType>, "Field type must be JSON-serializable");
json[name] = field;
}
}
catch (const std::exception& e) {
std::cerr << "Serialization error for field " << name << ": " << e.what() << "\n";
}
});
return json;
}
static T fromJson(const std::string& json) {
return fromJson(JsonType::parse(json));
}
// Deserialization: Convert JSON to struct
static T fromJson(const JsonType& json) {
std::cout << "Input JSON:\n" << json.dump(2) << "\n";
T object{};
boost::pfr::for_each_field_with_name(object, [&json](std::string_view const name, auto& field) {
std::cout << "Checking key: " << name << "\n";
try {
using ChildType = std::remove_cvref_t<decltype(field)>;
if (json.contains(name)) {
std::cout << "Found key: " << name << "\n";
if constexpr (IsReflectable<ChildType>) {
field = JsonSer<ChildType>::fromJson(json[name]);
}
else if constexpr (IsVector<ChildType>) {
if (json[name].is_array()) {
field.clear();
for (const auto& item : json[name]) {
if constexpr (IsReflectable<typename ChildType::value_type>) {
field.push_back(JsonSer<typename ChildType::value_type>::fromJson(item));
}
else {
static_assert(JsonSerializable<typename ChildType::value_type>, "Vector element type must be JSON-serializable");
field.push_back(item.get<typename ChildType::value_type>());
}
}
}
else {
std::cerr << "Field " << name << " is not an array\n";
}
}
else if constexpr (IsArray<ChildType>) {
if (json[name].is_array() && json[name].size() <= field.size()) {
std::size_t i = 0;
for (const auto& item : json[name]) {
if constexpr (IsReflectable<typename ChildType::value_type>) {
field[i] = JsonSer<typename ChildType::value_type>::fromJson(item);
}
else {
static_assert(JsonSerializable<typename ChildType::value_type>, "Array element type must be JSON-serializable");
field[i] = item.get<typename ChildType::value_type>();
}
++i;
}
}
else {
std::cerr << "Field " << name << " is not an array or size mismatch\n";
}
}
else {
static_assert(JsonSerializable<ChildType>, "Field type must be JSON-serializable");
field = json[name].get<ChildType>();
}
}
else {
std::cerr << "Key not found: " << name << "\n";
}
}
catch (const std::exception& e) {
std::cerr << "Deserialization error for field " << name << ": " << e.what() << "\n";
}
});
return object;
}
};
//int test_print_struct() {
int main(){
Person p{ "Alice", 30, 1.75 };
try {
auto result_json = JsonSer<Person>::toJson(p).dump(4);
std::cout << result_json << std::endl;
Person ccc = JsonSer<Person>::fromJson(result_json);
std::cout << ccc.name << std::endl;
}
catch (std::exception& e)
{
std::cout << e.what() << std::endl;
}
return 0;
}
更多推荐
所有评论(0)