Die vorherige Version zur Lösung des Problems der Zuordnung zwischen der C ++ - Struktur und json stellte sich wie der erste Pfannkuchen heraus - ein Klumpen. Glücklicherweise ist die Entwicklung ein iterativer Prozess und es wird immer eine zweite Version hinter der ersten Version geben. Die Kommentare (danke an alle) und die Lochanalyse im ersten Pfannkuchen haben einige Verbesserungen gebracht.
Was war schlecht
- Es ist unmöglich, gewöhnliche C ++ - Strukturen (einschließlich der bereits vorhandenen) zu verwenden. Alle Strukturen müssen in besonderer Weise von Grund auf neu definiert werden
- Das Json-Objekt kann nur einer speziell definierten Struktur zugeordnet werden
- Das Json-Array kann nur einer speziellen Klasse zugeordnet werden
- Es ist unmöglich, stl-Behälter zu verwenden
- Makros sind einfach notwendig (es ist ohne sie möglich, aber die Registrierung von Methoden zum Setzen von Feldern ist starr mit der Initialisierung dieser Felder verbunden, daher ist die Strukturdefinition ohne Makros nicht lesbar).
- die Anzeige ist in keiner Weise konfigurierbar, d.h. Es können beispielsweise keine Standardwerte oder Wertgrenzen festgelegt werden
Wie es jetzt wurde
Die Registrierung der Felder, die an der Anzeige teilnehmen, ist nicht mehr an die Struktur gebunden. Verwenden Sie die Funktion, um sich zu registrieren
reg(V T::* ptr, std::string const & name, Options<U>&& ... options);
ptr
- Zeiger auf das Feldname
- Feldnameoptions
- Anzeigeoptionen
Folgendes kann als Feldtyp verwendet werden:
- Bool
- char, unsigned char, short, unsigned short, int unsigned int, long, long long
- schweben, doppelt
- 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
— jsonindent
— ( , )
#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-Objekte können sowohl einer speziell definierten Struktur (diese Möglichkeit bleibt bestehen) als auch gewöhnlichen Strukturen zugeordnet werden
- Json-Arrays können std :: vector und std :: list zugeordnet werden. Die allgemeinen Anforderungen für Container, auf die Arrays abgebildet werden können, sind noch nicht vollständig festgelegt.
- JSON-Objekte können assoziativen Containern zugeordnet werden, mit der Einschränkung, dass der Schlüssel eine Zeichenfolge sein muss. Die allgemeinen Anforderungen an Container sowie an Arrays sind noch nicht vollständig erfüllt.
- Makros sind unnötig und sicherlich nicht notwendig. Die Möglichkeit, sie zu verwenden, blieb (als Option) während der Registrierung in Verbindung mit der Initialisierung der Felder bestehen. Aber höchstwahrscheinlich wird es geschnitten.
- Die Anzeige kann mithilfe von Optionen angepasst werden