JSON in C++
Tags: cpp, codenewbie, tutorial, json
Published: 2019-12-02 07:53:49


**Third article in series: Modern C++**

Modern C++ series:

- [Intro to Modern C++](http://zigabrencic.com/posts/2019-11-05.html)
- [C++ the python way](http://zigabrencic.com/posts/2019-11-12.html)

One thing in `python` that's super useful are dictionaries and `JSON`. They allow flexible data structures. What about `JSON` structures? They are not possible in a statically typed language like `C++`. We'll modern `C++` can handle `JSON` believe it or not :)
`C++` itself doesn't provide `JSON`, but there are a few options that bring `JSON` type data structure to `C++`.  

I personally use [C++ JSON library nlohman](https://github.com/nlohmann/json). There are other libraries, though, so take your pick. I like `nlohman JSON` lib because it's a single header file library (drop header file into the project). Or it can also be used as a dependency. It depends if you want to ship the `JSON` lib with your software or allow the user to add it as a dependency.

What can the `JSON` library do? Well, quite a lot, but the syntax and usage can be quite confusing, so I'll provide a few examples to clear things out.

**Note:** I'm assuming ' `using nlohmann::json;` to write less syntax. 

To create a `JSON` object, we simply do:

```
json data;
```

and then add elements to it:

```
// vector
data["M_final"] = std::vector<double>(N);

// a double
data["beta"] = 10.0;
```

or any other structure from `STL` library. Some `STL` structures are not supported though most are. More on adding custom structures to `JSON` later. 

There are a lot more options on how to construct the `json` object. For example, we can actually write the `JSON` format in the program, but I prefer to load `JSON` data structures from an external file.  `json` object creation inside the codebase:

```
json data = R"(
    {
        "happy": true,
        "pi": 3.141
    }
)"_json;
```

For more construction options, look into the docs. The library has a ton of other functionality `STL` like access, for example, but really read the docs if you are interested in more.

## Read & write JSON files

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/joqihg87haqj76iymfeb.png)

How do we load `JSON` file into the `JSON` data object from `C++`? We'll quite easyly. If we specify:

```
std::string path = "path to json file";
std::string file_name = "json_file_name";
```
we then load the file with few lines of code:

```
json data;
std::ifstream file(path + "/" + file_name + ".json");
file >> data;
```

Side note. You need to include `#include <iostream>` and `#include <fstream>` libraries. But they are in `STL` so no need for messy installs.

Then to store to the `JSON` file:

```
std::ofstream file(path + "/" + file_name + ".json");
file << std::setw(4) << data << std::endl;
```

## Custom JSON serializers

So let's say we want to store a custom data structure to a `JSON` file. For that, we need to define a serializer. JSON serializer tells our library how it should convert a `C++` object into a format that can be written into a `JSON` file. Or in other words, it tells the software how to load the `JSON` file into appropriate `C++` data structure.  

For example, let's say we want to be able to store `std::complex<double>` to JSON. Then we can expand the `std` namespace with two methods `to_json` and `from_json`:

```
namespace std {

    /// std::complex<double>
    void to_json(json &j, const std::complex<double> &complex_number) {
        j = json{{"re", complex_number.real()},
                 {"im", complex_number.imag()}};
    }

    void from_json(const json &j, std::complex<double> &complex_number) {
        complex_number.real(j.at("re").get<double>());
        complex_number.imag(j.at("im").get<double>());
    }
}
```

Or to add a structure of type `person`:

```
struct person_t {
    std::string name;
    std::string address;
    int age;
};

void to_json(json &j, const person_t &p) {
    j = json{{"name",  p.name},
             {"address", p.address},
             {"age",   p.age}};
}

void from_json(const json &j, person_t &p) {
    j.at("name").get_to(p.name);
    j.at("address").get_to(p.address);
    j.at("age").get_to(p.age);
}
```

By providing `to_json` and `from_json` we allow the program to automatically map our data structure to the `JSON` format. Now we can store a `person` structure to the `JSON` file via:

```
person_t p;
// define person: name, address, age
json data;
data["person"] = p;
```

If we stored `json data` now into a `JSON` file, the content would be:

```
"person": {
    "name": "John",
    "address": "web",
    "age": "31"
}
```

That's it. OK when reading back from `JSON` file we actually need to provide the data structure type before we can get the `C++` function. For example to retrieve our person object:

```
json data; // contains person object but in string format
auto p = data.at("person").get<person_t>();
```

I know that's not as pretty as in `python`, but if you store the type of the data structures when you create the `JSON` file, you can use a little trick. You can write an extra wrapper around `json` library that allows you to make calls of type:

```
enhanced_json data;
person_p p = data.at("person");
```

In the above case, you handle data loading based on the data type in the `JSON` file inside the `enhanced_json` object using the `at` function. To get the `enhanced_json` object, you need a few if statements and auto.

Sure all the above software will add overhead and make your code slower. So if you need fast data storage for large amounts of data, this automatic serialization is probably not a good idea. I would argue that JSON is not a good idea if you need to read and store a lot of data. But if you need `C++` to do a lot of data crunching and need a bit of storage. Then `JSON` interface can tremendously speed up your workflow. 

## JSON doesn't make C++ totally python

In the next article I'll dive into the use of C++ JSON data structures to speed up the analysis workflow. Until then, if you know any more tricks that make C++ more pythonic, let me know.