[C++, Программирование] Отображение данных в формате json на структуру c++ и обратно (работа над ошибками)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Предыдущий вариант решения задачи отображения между структурой с++ и json получился как первый блин — комом. К счастью, разработка — процесс итерационный, и за первой версией всегда будет вторая. Комментарии (спасибо всем) и анализ дырок в первом блине позволили кое-что улучшить.
Что было плохо
- невозможно использовать обычные структуры с++ (в том числе уже существующие). Все структуры необходимо определять с нуля специальным образом
- Json объект можно отображать только на специальным образом определенную структуру
- Json массив можно отображать только на специальный класс
- невозможно использовать stl контейнеры
- макросы просто необходимы (можно и без них, но регистрация методов установки полей жестко совмещена с инициализацией этих полей, поэтому без макросов определение структуры нечитаемо)
- отображение никак не настраивается, т.е. нельзя задать, например, значения по умолчанию или пределы значений
Как стало теперь
Регистрация полей, которые будут участвовать в отображении, больше не привязана к структуре. Для регистрации используется функция
reg(V T::* ptr, std::string const & name, Options<U>&& ... options);
- ptr — указатель на поле
- name — имя поля
- options — опции отображения
В качестве типов полей могут быть использованы:
- bool
- char, unsigned char, short, unsigned short, int unsigned int, long, long long
- float, double
- std::string
- std::list
- std::vector
- std::map (ключем может быть только std::string)
- std::unordered_map (ключем может быть только std::string)
- std::multimap (ключем может быть только std::string)
- std::unordered_multimap (ключем может быть только std::string)
- структуры с++
- перечисления
например
struct Friend {
std::string name;
std::list<int> counters;
};
struct MiB {
std::list<Friend> friends;
std::vector<std::list<std::string>> groups;
std::map<std::string, std::vector<std::string>> books;
};
struct_mapping::reg(&Friend::name, "name");
struct_mapping::reg(&Friend::counters, "counters");
struct_mapping::reg(&MiB::friends, "friends");
struct_mapping::reg(&MiB::groups, "groups");
struct_mapping::reg(&MiB::books, "books");
После регистрации, как и раньше, вызывается
map_json_to_struct(T & result_struct, std::basic_istream<char> & json_data);
- result_struct — ссылка на результирующую структуру
- json_data — ссылка на входной поток json данных
В процессе отображения проверяется соответствие типов полей типам устанавливаемого значения и для чисел устанавливаемое значение проверяется на выход из диапазона значений типа поля. При несоответствии типов или выхода значения за границы диапазона генерируются исключения.
Небольшой полный пример выглядит так
#include <iostream>
#include <sstream>
#include "struct_mapping/struct_mapping.h"
struct Planet {
bool giant;
long long surface_area;
double mass;
std::string satellite;
};
int main() {
struct_mapping::reg(&Planet::giant, "giant");
struct_mapping::reg(&Planet::surface_area, "surface_area");
struct_mapping::reg(&Planet::mass, "mass");
struct_mapping::reg(&Planet::satellite, "satellite");
Planet earth;
std::istringstream json_data(R"json(
{
"giant": false,
"surface_area": 510072000000000,
"mass": 5.97237e24,
"satellite": "Moon"
}
)json");
struct_mapping::map_json_to_struct(earth, json_data);
std::cout << "earth" << std::endl;
std::cout << " giant : " << std::boolalpha << earth.giant << std::endl;
std::cout << " surface_area : " << earth.surface_area << std::endl;
std::cout << " mass : " << earth.mass << std::endl;
std::cout << " satellite : " << earth.satellite << std::endl;
}
что дает в результате
earth
giant : false
surface_area : 510072000000000
mass : 5.97237e+24
satellite : Moon
Использование перечислений
Библиотека ожидает, что перечисления в json представляются в виде строк. Поэтому для использования перечислений требуется установить методы преобразования из строки в значение перечисления и наоборот, используя:
MemberString::set(From function_from_string_, To function_to_string_);
- function_from_string_ — функция преобразования из строки в значение перечисления
- function_to_string_ — функция преобразования из значения перечисления в строку
например
enum class Color {
red,
blue,
green,
};
struct_mapping::MemberString<Color>::set(
[] (const std::string & value) {
if (value == "red") return Color::red;
if (value == "green") return Color::green;
if (value == "blue") return Color::blue;
throw struct_mapping::StructMappingException("bad convert '"+value+"' to Color");
},
[] (Color value) {
switch (value) {
case Color::red: return "red";
case Color::green: return "green";
default: return "blue";
}
});
в остальном использование перечислений аналогично остальным типам
#include <iostream>
#include <list>
#include <map>
#include <sstream>
#include <string>
#include "struct_mapping/struct_mapping.h"
namespace sm = struct_mapping;
enum class Color {
red,
blue,
green,
};
Color color_from_string(const std::string & value) {
if (value == "red") return Color::red;
if (value == "blue") return Color::blue;
return Color::green;
}
std::string color_to_string(Color color) {
switch (color) {
case Color::red: return "red";
case Color::green: return "green";
default: return "blue";
}
}
struct Palette {
Color main_color;
Color background_color;
std::list<Color> special_colors;
std::map<std::string, Color> colors;
friend std::ostream & operator<<(std::ostream & os, const Palette & o) {
os << "main_color : " << color_to_string(o.main_color) << std::endl;
os << "background_color : " << color_to_string(o.background_color) << std::endl;
os << "special_colors : ";
for (auto color : o.special_colors)
os << color_to_string(color) << ", ";
os << std::endl << "colors : ";
for (auto [name, color] : o.colors)
os << "[" << name << ", " << color_to_string(color) << "], ";
os << std::endl;
return os;
}
};
int main() {
sm::MemberString<Color>::set(color_from_string, color_to_string);
sm::reg(&Palette::main_color, "main_color", sm::Required{});
sm::reg(&Palette::background_color, "background_color", sm::Default{Color::blue});
sm::reg(&Palette::special_colors, "special_colors");
sm::reg(&Palette::colors, "colors");
Palette palette;
std::istringstream json_data(R"json(
{
"main_color": "green",
"special_colors": ["green", "green", "red"],
"colors": {
"dark": "green",
"light": "red",
"neutral": "blue"
}
}
)json");
sm::map_json_to_struct(palette, json_data);
std::cout << palette << std::endl;
}
результат
main_color : green
background_color : blue
special_colors : green, green, red,
colors : [dark, green], [light, red], [neutral, blue],
Опции отображения
Появилась возможность задавать при регистрации поля опции, которые будут использоваться при отображении этого поля
- Bounds
- Default
- NotEmpty
- Required
Bounds
Устанавливает диапазон значений, в котором (включая границы диапазона) должно находится устанавливаемое значение. Применима для целочисленных типов и типов с плавающей точкой. Опция принимает два параметра — границы диапазона. Генерирует исключение при выходе устанавливаемого в процессе отображения значения за границы.
Bounds{нижняя граница, верхняя граница}
Пример задания опции:
reg(&Stage::engine_count, "engine_count", Bounds{1, 31});
Default
Устанавливает значение по умолчанию для поля. Применима для bool, целочисленных типов, типов с плавающей точкой, строк, контейнеров, структур с++ и перечислений. Опция принимает один параметр — значение по умолчанию.
Default{значение по умолчанию}
Пример задания опции:
reg(&Stage::engine_count, "engine_count", Default{3});
NotEmpty
Отмечает, что для поля не может быть установлено пустое значение. Применима для строк и контейнеров. Опция не принимает параметров. Генерирует исключение, если после завершения отображения значением поля является пустая строка или пустой контейнер.
Пример задания опции:
reg(&Spacecraft::name, "name", NotEmpty{}));
Required
Отмечает, что для поля обязательно должно быть установлено значение. Применима для bool, целочисленных типов, типов с плавающей точкой, строк, контейнеров, структур с++ и перечислений. Опция не принимает параметров. Генерирует исключение, если после завершения отображения значение для поля не было установлено.
Пример задания опции:
reg(&Spacecraft::name, "name", Required{}));
Пример использования опций
#include <iostream>
#include <list>
#include <map>
#include <sstream>
#include <string>
#include "struct_mapping/struct_mapping.h"
namespace sm = struct_mapping;
struct Stage {
unsigned short engine_count;
std::string fuel;
long length;
friend std::ostream & operator<<(std::ostream & os, const Stage & o) {
os << " engine_count : " << o.engine_count << std::endl;
os << " fuel : " << o.fuel << std::endl;
os << " length : " << o.length << std::endl;
return os;
}
};
struct Spacecraft {
bool in_development;
std::string name;
int mass;
std::map<std::string, Stage> stages;
std::list<std::string> crew;
friend std::ostream & operator<<(std::ostream & os, const Spacecraft & o) {
os << "in_development : " << std::boolalpha << o.in_development << std::endl;
os << "name : " << o.name << std::endl;
os << "mass : " << o.mass << std::endl;
os << "stages: " << std::endl;
for (auto& s : o.stages) os << " " << s.first << std::endl << s.second;
os << "crew: " << std::endl;
for (auto& p : o.crew) os << " " << p << std::endl;
return os;
}
};
int main() {
sm::reg(&Stage::engine_count, "engine_count", sm::Default{6}, sm::Bounds{1, 31});
sm::reg(&Stage::fuel, "fuel", sm::Default{"subcooled"});
sm::reg(&Stage::length, "length", sm::Default{50});
sm::reg(&Spacecraft::in_development, "in_development", sm::Required{});
sm::reg(&Spacecraft::name, "name", sm::NotEmpty{});
sm::reg(&Spacecraft::mass, "mass",
sm::Default{5000000}, sm::Bounds{100000, 10000000});
sm::reg(&Spacecraft::stages, "stages", sm::NotEmpty{});
sm::reg(&Spacecraft::crew, "crew",
sm::Default{std::list<std::string>{"Arthur", "Ford", "Marvin"}});
Spacecraft starship;
std::istringstream json_data(R"json(
{
"in_development": false,
"name": "Vostok",
"stages": {
"first": {
"engine_count": 31,
"fuel": "compressed gas",
"length": 70
},
"second": {}
}
}
)json");
sm::map_json_to_struct(starship, json_data);
std::cout << starship << std::endl;
}
результат
in_development : false
name : Vostok
mass : 5000000
stages:
first
engine_count : 31
fuel : compressed gas
length : 70
second
engine_count : 6
fuel : subcooled
length : 50
crew:
Arthur
Ford
Marvin
Обратное отображение структуры c++ на json
Для обратного отображения структуры на json необходимо предварительно зарегистрировать все поля всех структур, которые требуется отображать, используя для каждого поля
reg(V T::* ptr, std::string const & name, Options<U>&& ... options);
и вызвать непосредственно для обратного отображения функцию
map_struct_to_json(T & source_struct, std::basic_ostream<char> & json_data, std::string indent);
- source_struct — ссылка на исходную структуру
- json_data — ссылка на выходной поток json данных
- indent — отступ (если задан, делает выходной формат лучше читаемым)
#include <iostream>
#include <sstream>
#include "struct_mapping/struct_mapping.h"
struct OceanPart {
std::string name;
double average_depth;
std::vector<int> temperature;
};
struct OceanColor {
std::string name;
};
struct Ocean {
double water_volume;
long long surface_area;
bool liquid;
std::string name;
OceanColor color;
std::vector<OceanPart> parts;
};
struct Planet {
bool giant;
long long surface_area;
double mass;
double volume;
long long orbital_period;
std::string name;
bool terrestrial;
std::string shape;
Ocean ocean;
};
int main() {
struct_mapping::reg(&OceanPart::name, "name");
struct_mapping::reg(&OceanPart::average_depth, "average_depth");
struct_mapping::reg(&OceanPart::temperature, "temperature");
struct_mapping::reg(&OceanColor::name, "name");
struct_mapping::reg(&Ocean::water_volume, "water_volume");
struct_mapping::reg(&Ocean::surface_area, "surface_area");
struct_mapping::reg(&Ocean::liquid, "liquid");
struct_mapping::reg(&Ocean::name, "name");
struct_mapping::reg(&Ocean::color, "color");
struct_mapping::reg(&Ocean::parts, "parts");
struct_mapping::reg(&Planet::giant, "giant");
struct_mapping::reg(&Planet::surface_area, "surface_area");
struct_mapping::reg(&Planet::mass, "mass");
struct_mapping::reg(&Planet::volume, "volume");
struct_mapping::reg(&Planet::orbital_period, "orbital_period");
struct_mapping::reg(&Planet::name, "name");
struct_mapping::reg(&Planet::terrestrial, "terrestrial");
struct_mapping::reg(&Planet::shape, "shape");
struct_mapping::reg(&Planet::ocean, "ocean");
Planet earth;
earth.giant = false;
earth.terrestrial = true;
earth.surface_area = 510072000;
earth.orbital_period = 365 * 24 * 3600;
earth.mass = 5.97237e24;
earth.name = "Terra";
earth.volume = 1.08321e12;
earth.shape = "nearly spherical";
earth.ocean.water_volume = 1332000000;
earth.ocean.surface_area = 361132000;
earth.ocean.liquid = true;
earth.ocean.name = "World Ocean";
earth.ocean.color.name = "blue";
OceanPart pacific;
pacific.name = "Pacific Ocean";
pacific.average_depth = 4.280111;
pacific.temperature = std::vector<int>{-3, 5, 12};
OceanPart atlantic;
atlantic.name = "Atlantic Ocean";
atlantic.average_depth = 3.646;
atlantic.temperature = std::vector<int>{-3, 0};
earth.ocean.parts.push_back(pacific);
earth.ocean.parts.push_back(atlantic);
std::ostringstream json_data;
struct_mapping::map_struct_to_json(earth, json_data, " ");
std::cout << json_data.str() << std::endl;
}
результат
{
"giant": false,
"surface_area": 510072000,
"mass": 5.97237e+24,
"volume": 1.08321e+12,
"orbital_period": 31536000,
"name": "Terra",
"terrestrial": true,
"shape": "nearly spherical",
"ocean": {
"water_volume": 1.332e+09,
"surface_area": 361132000,
"liquid": true,
"name": "World Ocean",
"color": {
"name": "blue"
},
"parts": [
{
"name": "Pacific Ocean",
"average_depth": 4.28011,
"temperature": [
-3,
5,
12
]
},
{
"name": "Atlantic Ocean",
"average_depth": 3.646,
"temperature": [
-3,
0
]
}
]
}
}
В итоге
- использовать обычные структуры с++ можно (и нужно)
- Json объекты можно отображать как на специальным образом определенную структуру (такая возможность осталась), так и на обычные структуры
- Json массивы можно отображать на std::vector и std::list. Общие требования к контейнерам на которые можно отображать массивы пока не полностью сформированы.
- json объекты можно отображать на ассоциативные контейнеры, с ограничением на то, что ключ должен быть строкой. Общие требования к контейнерам, как и с массивами, пока не полностью сформированы.
- макросы не нужны и уж точно не необходимы. Возможность их использования осталась (как вариант) при регистрации, совмещенной с инициализацией полей. Но скорее всего, будет выпилена.
- отображение можно настраивать с помощью опций
Библиотека доступна на GitHub
===========
Источник:
habr.com
===========
Похожие новости:
- [Программирование, Разработка веб-сайтов, Учебный процесс в IT] Задачки для фронтенд-тренировки: клоны CodeSandbox, Robinhood, Whoishiring, Stackoverflow (перевод)
- [Программирование, Разработка игр, Алгоритмы] Armored Warfare: Проект Армата. Хроматическая аберрация
- [Тестирование IT-систем, Java, API, Kotlin] Как Kotlin может помочь в тестировании API: кейс Русфинанс Банка
- [Ненормальное программирование, Clojure, Функциональное программирование, Программирование] Функциональное программирование, знакомься — ООП (перевод)
- [C++, Python, Учебный процесс в IT] Яндекс.Практикум запустил онлайн-курсы для Junior-разработчиков
- [*nix, Java, Программирование, Сетевые технологии] Как скачать файл порциями?
- [Высокая производительность, Информационная безопасность, Криптография, Патентование, Программирование] Генератор псевдослучайных чисел большой разрядности
- [C, Программирование микроконтроллеров, Системное программирование, Учебный процесс в IT] Очередная книга про разработку операционных систем
- [.NET, C#, Анализ и проектирование систем, Программирование] Применение CQRS & Event Sourcing в создании платформы для проведения онлайн-аукционов
- [Конференции, Ненормальное программирование, Программирование, Спортивное программирование] Контур стал организатором ICFPC 2020
Теги для поиска: #_c++, #_programmirovanie (Программирование), #_c++, #_json, #_c++, #_programmirovanie (
Программирование
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 19:54
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Предыдущий вариант решения задачи отображения между структурой с++ и json получился как первый блин — комом. К счастью, разработка — процесс итерационный, и за первой версией всегда будет вторая. Комментарии (спасибо всем) и анализ дырок в первом блине позволили кое-что улучшить. Что было плохо
Как стало теперь Регистрация полей, которые будут участвовать в отображении, больше не привязана к структуре. Для регистрации используется функция reg(V T::* ptr, std::string const & name, Options<U>&& ... options);
В качестве типов полей могут быть использованы:
например struct Friend {
std::string name; std::list<int> counters; }; struct MiB { std::list<Friend> friends; std::vector<std::list<std::string>> groups; std::map<std::string, std::vector<std::string>> books; }; struct_mapping::reg(&Friend::name, "name"); struct_mapping::reg(&Friend::counters, "counters"); struct_mapping::reg(&MiB::friends, "friends"); struct_mapping::reg(&MiB::groups, "groups"); struct_mapping::reg(&MiB::books, "books"); После регистрации, как и раньше, вызывается map_json_to_struct(T & result_struct, std::basic_istream<char> & json_data);
В процессе отображения проверяется соответствие типов полей типам устанавливаемого значения и для чисел устанавливаемое значение проверяется на выход из диапазона значений типа поля. При несоответствии типов или выхода значения за границы диапазона генерируются исключения. Небольшой полный пример выглядит так #include <iostream>
#include <sstream> #include "struct_mapping/struct_mapping.h" struct Planet { bool giant; long long surface_area; double mass; std::string satellite; }; int main() { struct_mapping::reg(&Planet::giant, "giant"); struct_mapping::reg(&Planet::surface_area, "surface_area"); struct_mapping::reg(&Planet::mass, "mass"); struct_mapping::reg(&Planet::satellite, "satellite"); Planet earth; std::istringstream json_data(R"json( { "giant": false, "surface_area": 510072000000000, "mass": 5.97237e24, "satellite": "Moon" } )json"); struct_mapping::map_json_to_struct(earth, json_data); std::cout << "earth" << std::endl; std::cout << " giant : " << std::boolalpha << earth.giant << std::endl; std::cout << " surface_area : " << earth.surface_area << std::endl; std::cout << " mass : " << earth.mass << std::endl; std::cout << " satellite : " << earth.satellite << std::endl; } что дает в результате earth
giant : false surface_area : 510072000000000 mass : 5.97237e+24 satellite : Moon Использование перечислений Библиотека ожидает, что перечисления в json представляются в виде строк. Поэтому для использования перечислений требуется установить методы преобразования из строки в значение перечисления и наоборот, используя: MemberString::set(From function_from_string_, To function_to_string_);
например enum class Color {
red, blue, green, }; struct_mapping::MemberString<Color>::set( [] (const std::string & value) { if (value == "red") return Color::red; if (value == "green") return Color::green; if (value == "blue") return Color::blue; throw struct_mapping::StructMappingException("bad convert '"+value+"' to Color"); }, [] (Color value) { switch (value) { case Color::red: return "red"; case Color::green: return "green"; default: return "blue"; } }); в остальном использование перечислений аналогично остальным типам #include <iostream>
#include <list> #include <map> #include <sstream> #include <string> #include "struct_mapping/struct_mapping.h" namespace sm = struct_mapping; enum class Color { red, blue, green, }; Color color_from_string(const std::string & value) { if (value == "red") return Color::red; if (value == "blue") return Color::blue; return Color::green; } std::string color_to_string(Color color) { switch (color) { case Color::red: return "red"; case Color::green: return "green"; default: return "blue"; } } struct Palette { Color main_color; Color background_color; std::list<Color> special_colors; std::map<std::string, Color> colors; friend std::ostream & operator<<(std::ostream & os, const Palette & o) { os << "main_color : " << color_to_string(o.main_color) << std::endl; os << "background_color : " << color_to_string(o.background_color) << std::endl; os << "special_colors : "; for (auto color : o.special_colors) os << color_to_string(color) << ", "; os << std::endl << "colors : "; for (auto [name, color] : o.colors) os << "[" << name << ", " << color_to_string(color) << "], "; os << std::endl; return os; } }; int main() { sm::MemberString<Color>::set(color_from_string, color_to_string); sm::reg(&Palette::main_color, "main_color", sm::Required{}); sm::reg(&Palette::background_color, "background_color", sm::Default{Color::blue}); sm::reg(&Palette::special_colors, "special_colors"); sm::reg(&Palette::colors, "colors"); Palette palette; std::istringstream json_data(R"json( { "main_color": "green", "special_colors": ["green", "green", "red"], "colors": { "dark": "green", "light": "red", "neutral": "blue" } } )json"); sm::map_json_to_struct(palette, json_data); std::cout << palette << std::endl; } результат main_color : green
background_color : blue special_colors : green, green, red, colors : [dark, green], [light, red], [neutral, blue], Опции отображения Появилась возможность задавать при регистрации поля опции, которые будут использоваться при отображении этого поля
Bounds Устанавливает диапазон значений, в котором (включая границы диапазона) должно находится устанавливаемое значение. Применима для целочисленных типов и типов с плавающей точкой. Опция принимает два параметра — границы диапазона. Генерирует исключение при выходе устанавливаемого в процессе отображения значения за границы. Bounds{нижняя граница, верхняя граница}
Пример задания опции: reg(&Stage::engine_count, "engine_count", Bounds{1, 31});
Default Устанавливает значение по умолчанию для поля. Применима для bool, целочисленных типов, типов с плавающей точкой, строк, контейнеров, структур с++ и перечислений. Опция принимает один параметр — значение по умолчанию. Default{значение по умолчанию}
Пример задания опции: reg(&Stage::engine_count, "engine_count", Default{3});
NotEmpty Отмечает, что для поля не может быть установлено пустое значение. Применима для строк и контейнеров. Опция не принимает параметров. Генерирует исключение, если после завершения отображения значением поля является пустая строка или пустой контейнер. Пример задания опции: reg(&Spacecraft::name, "name", NotEmpty{}));
Required Отмечает, что для поля обязательно должно быть установлено значение. Применима для bool, целочисленных типов, типов с плавающей точкой, строк, контейнеров, структур с++ и перечислений. Опция не принимает параметров. Генерирует исключение, если после завершения отображения значение для поля не было установлено. Пример задания опции: reg(&Spacecraft::name, "name", Required{}));
Пример использования опций #include <iostream>
#include <list> #include <map> #include <sstream> #include <string> #include "struct_mapping/struct_mapping.h" namespace sm = struct_mapping; struct Stage { unsigned short engine_count; std::string fuel; long length; friend std::ostream & operator<<(std::ostream & os, const Stage & o) { os << " engine_count : " << o.engine_count << std::endl; os << " fuel : " << o.fuel << std::endl; os << " length : " << o.length << std::endl; return os; } }; struct Spacecraft { bool in_development; std::string name; int mass; std::map<std::string, Stage> stages; std::list<std::string> crew; friend std::ostream & operator<<(std::ostream & os, const Spacecraft & o) { os << "in_development : " << std::boolalpha << o.in_development << std::endl; os << "name : " << o.name << std::endl; os << "mass : " << o.mass << std::endl; os << "stages: " << std::endl; for (auto& s : o.stages) os << " " << s.first << std::endl << s.second; os << "crew: " << std::endl; for (auto& p : o.crew) os << " " << p << std::endl; return os; } }; int main() { sm::reg(&Stage::engine_count, "engine_count", sm::Default{6}, sm::Bounds{1, 31}); sm::reg(&Stage::fuel, "fuel", sm::Default{"subcooled"}); sm::reg(&Stage::length, "length", sm::Default{50}); sm::reg(&Spacecraft::in_development, "in_development", sm::Required{}); sm::reg(&Spacecraft::name, "name", sm::NotEmpty{}); sm::reg(&Spacecraft::mass, "mass", sm::Default{5000000}, sm::Bounds{100000, 10000000}); sm::reg(&Spacecraft::stages, "stages", sm::NotEmpty{}); sm::reg(&Spacecraft::crew, "crew", sm::Default{std::list<std::string>{"Arthur", "Ford", "Marvin"}}); Spacecraft starship; std::istringstream json_data(R"json( { "in_development": false, "name": "Vostok", "stages": { "first": { "engine_count": 31, "fuel": "compressed gas", "length": 70 }, "second": {} } } )json"); sm::map_json_to_struct(starship, json_data); std::cout << starship << std::endl; } результат in_development : false
name : Vostok mass : 5000000 stages: first engine_count : 31 fuel : compressed gas length : 70 second engine_count : 6 fuel : subcooled length : 50 crew: Arthur Ford Marvin Обратное отображение структуры c++ на json Для обратного отображения структуры на json необходимо предварительно зарегистрировать все поля всех структур, которые требуется отображать, используя для каждого поля reg(V T::* ptr, std::string const & name, Options<U>&& ... options);
и вызвать непосредственно для обратного отображения функцию map_struct_to_json(T & source_struct, std::basic_ostream<char> & json_data, std::string indent);
#include <iostream>
#include <sstream> #include "struct_mapping/struct_mapping.h" struct OceanPart { std::string name; double average_depth; std::vector<int> temperature; }; struct OceanColor { std::string name; }; struct Ocean { double water_volume; long long surface_area; bool liquid; std::string name; OceanColor color; std::vector<OceanPart> parts; }; struct Planet { bool giant; long long surface_area; double mass; double volume; long long orbital_period; std::string name; bool terrestrial; std::string shape; Ocean ocean; }; int main() { struct_mapping::reg(&OceanPart::name, "name"); struct_mapping::reg(&OceanPart::average_depth, "average_depth"); struct_mapping::reg(&OceanPart::temperature, "temperature"); struct_mapping::reg(&OceanColor::name, "name"); struct_mapping::reg(&Ocean::water_volume, "water_volume"); struct_mapping::reg(&Ocean::surface_area, "surface_area"); struct_mapping::reg(&Ocean::liquid, "liquid"); struct_mapping::reg(&Ocean::name, "name"); struct_mapping::reg(&Ocean::color, "color"); struct_mapping::reg(&Ocean::parts, "parts"); struct_mapping::reg(&Planet::giant, "giant"); struct_mapping::reg(&Planet::surface_area, "surface_area"); struct_mapping::reg(&Planet::mass, "mass"); struct_mapping::reg(&Planet::volume, "volume"); struct_mapping::reg(&Planet::orbital_period, "orbital_period"); struct_mapping::reg(&Planet::name, "name"); struct_mapping::reg(&Planet::terrestrial, "terrestrial"); struct_mapping::reg(&Planet::shape, "shape"); struct_mapping::reg(&Planet::ocean, "ocean"); Planet earth; earth.giant = false; earth.terrestrial = true; earth.surface_area = 510072000; earth.orbital_period = 365 * 24 * 3600; earth.mass = 5.97237e24; earth.name = "Terra"; earth.volume = 1.08321e12; earth.shape = "nearly spherical"; earth.ocean.water_volume = 1332000000; earth.ocean.surface_area = 361132000; earth.ocean.liquid = true; earth.ocean.name = "World Ocean"; earth.ocean.color.name = "blue"; OceanPart pacific; pacific.name = "Pacific Ocean"; pacific.average_depth = 4.280111; pacific.temperature = std::vector<int>{-3, 5, 12}; OceanPart atlantic; atlantic.name = "Atlantic Ocean"; atlantic.average_depth = 3.646; atlantic.temperature = std::vector<int>{-3, 0}; earth.ocean.parts.push_back(pacific); earth.ocean.parts.push_back(atlantic); std::ostringstream json_data; struct_mapping::map_struct_to_json(earth, json_data, " "); std::cout << json_data.str() << std::endl; } результат {
"giant": false, "surface_area": 510072000, "mass": 5.97237e+24, "volume": 1.08321e+12, "orbital_period": 31536000, "name": "Terra", "terrestrial": true, "shape": "nearly spherical", "ocean": { "water_volume": 1.332e+09, "surface_area": 361132000, "liquid": true, "name": "World Ocean", "color": { "name": "blue" }, "parts": [ { "name": "Pacific Ocean", "average_depth": 4.28011, "temperature": [ -3, 5, 12 ] }, { "name": "Atlantic Ocean", "average_depth": 3.646, "temperature": [ -3, 0 ] } ] } } В итоге
Библиотека доступна на GitHub =========== Источник: habr.com =========== Похожие новости:
Программирование ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 19:54
Часовой пояс: UTC + 5