📜 ⬆️ ⬇️

What would JSON support look like in modern C ++?

Well in terms of JSON support, Javascript programmers live - for some incredible coincidence there JSON is included in the specification of the language itself: there is JSON - there is an object. Conveniently. The situation is also good in languages ​​where JSON is not included in the language itself, but is supported by the standard library (Python, Ruby): import the module - and you're done.

The life of C ++ programmers has never been particularly simple - we don’t have JSON support either at the language level or in the standard library. And probably never will be. “I also found a problem!” Experienced colleagues will tell me, “It should not be there, C ++ comes without a“ battery ”. To solve this problem, we ... "and here they are divided into two camps:

1. "We use a large framework (boost, Qt, POCO, other), which is used in all our projects and is able to 150,000 different things, including JSON."
2. “We adhere to the approach in which each task has its own lightweight library. In particular, for JSON, 150,000 years ago we chose the excellent% JSON_LIB% library, which works great. ”
')
Yes, it is. Here are just ...

What is bad approach to using frameworks
First, to pull a huge framework for the sake of JSON alone is somehow dull. Well, let's say you had a framework, and so on. But then you have to write work with JSON in terms of the framework, and this is usually a silent horror. Look, for example, at the Jt documentation in Qt — a bunch of native types like QJsonArray, QJsonDocument, QJsonObject, QJsonValue, etc. and have to use them. You can immediately forget about transferring the code to another project (where there is no framework). Well, or here's Boost: the JSON parser is very logical in the Boost.PropertyTree module. Yeah, so I would have guessed. Those. we are offered to dance not from the JSON format, but from the data structure “tree”, which can read itself including from JSON.

In general, the frameworks impose on us their own vision of the task, their own way of solving it, and strive to bind us to themselves forever. No, if you are sure that you have found the one and only unique framework and will be happy with it for the rest of your life - your will. But I somehow am not a supporter of such fatalism.


What is bad approach with the use of libraries
He is bad at this part: "... 150,000 years ago, we chose an excellent library ...". Most likely we are talking about something that began to be written almost at the time of DOS and, no doubt, it works, but at the same time, trying to be compatible with all platforms and standards of the language is completely behind the progress. Yes, everything compiles and works, even tests pass. But the library is completely unfamiliar with such things as the auto keyword, range-based loops, string literals, raw strings, displacement constructors, initialization lists, and other cool things that make code more efficient and more readable at the same time. But the library, created years ago, has obligations for backward compatibility, which means it just cannot take and add all this.


Let's dream a little.

And what if JSON was included in the standard library of the new standard C ++? What if it were written in terms of C ++ 11 \ 14 and without the requirements of backward compatibility with the old language standards? What if the syntax of this module would be tried to be as close as possible to JSON's native use “a la Javascript”, but at the same time keep the C ++ spirit (efficiency, minimum memory consumption, compatibility with STL)? What if it could be included in the project with one person and not worry about its assembly and linking? How would it all look and work?

And we have the answer to this question! Let's look at the JSON-library for C ++ written in accordance with all these principles, well, and generally written by people for people, and not strangers for predators, as is usually the case.


So, let us have to create such a JSON object here:

{ "name": "Habrahabr", "nothing": null, "answer": { "everything": 42 }, "companies": ["Infopulse", "TM"], "user": { "name": "tangro", "active": true } } 


Let's take and create!


We download github.com/nlohmann/json/blob/master/src/json.hpp , we include it in the cpp-file.

 #include "json.hpp" using json = nlohmann::json; 

 //   JSON- json j; 


 //  ,     std::string j["name"] = "Habrahabr"; 


 //     j["nothing"] = nullptr; 


 //     j["answer"]["everything"] = 42; 


 //    (   std::vector<std::string>) //   -    j["companies"] = { "Infopulse", "TM" }; 


 //     -         ""-"" j["user"] = { {"name", "tangro"}, {"active", true} }; 


By the way, using the latest feature, instead of all this you could write object creation very similar to the JSON format itself:

 json j2 = { {"name", "Habrahabr"}, {"nothing", nullptr}, {"answer", { {"everything", 42} }}, {"companies", {"Infopulse", "TM"}}, {"user", { {"name", "tangro"}, {"active", true} }} } 


So, where are all these fancy C ++ 11 chips?


And here they are.

 //      json j = "{ \"active\": true, \"pi\": 3.141 }"_json; 


 //  raw string json j = R"( { "active": true, "pi": 3.141 } )"_json; 


 //  auto auto j = json::parse("{ \"active\": true, \"pi\": 3.141 }"); 


 //  range-based for for (auto element : j) { std::cout << element << '\n'; } 


So, okay, I am an adherent of the "classic" style, show me compatibility with STL



 //  ,  "- std::vector" json j; j.push_back("foo"); j.push_back(1); j.push_back(true); 


 //  ,  "- std::map" json o; o["foo"] = 23; o["bar"] = false; 


 //   if (o.find("foo") != o.end()) { //  } 


 //    for (json::iterator it = j.begin(); it != j.end(); ++it) { std::cout << *it << '\n'; } 


 //   []   at(),  std::string const std::string tmp = j[0]; j[1] = 42; bool foo = j.at(2); 


 //      j.size(); // 3  j.empty(); // true  false j.type(); // json::value_t::array j.clear(); //  


 //    std::string s = j.dump(); 


Well, there is still support for creating JSON from any STL containers (std :: array, std :: vector, std :: deque, std :: forward_list, std :: list, std :: set, std :: multiset, std: : unordered_set, std :: unordered_multiset). For linearly ordered and ordered associative containers, the order of the elements will be preserved; for unordered-associative containers, of course, no.

So, almost convinced


And there is also a 100% test library coverage and a guarantee of the absence of memory leaks from Valgrind.

That's all.


In general, I understand that this is “just one more library for supporting JSON,” and in fact it is no different from a million others. But how is it still convenient to work with her!

Source: https://habr.com/ru/post/254075/


All Articles