zoukankan      html  css  js  c++  java
  • nlohmann 最优秀的C++序列化工具库 详细入门教程

    本文首发于个人博客https://kezunlin.me/post/f3c3eb8/,欢迎阅读最新内容!

    tutorial to use nlohmann json for serializing data with modern cpp

    Guide

    include

    #include <nlohmann/json.hpp>
    
    // for convenience
    using json = nlohmann::json;
    

    compile with

    -std=c++11

    CMakeLists.txt

    # CMakeLists.txt
    find_package(nlohmann_json 3.2.0 REQUIRED)
    ...
    add_library(foo ...)
    ...
    target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)
    

    Usage

    json demo

    {
      "pi": 3.141,
      "happy": true,
      "name": "Niels",
      "nothing": null,
      "answer": {
        "everything": 42
      },
      "list": [1, 0, 2],
      "object": {
        "currency": "USD",
        "value": 42.99
      }
    }
    

    with code

    // create an empty structure (null)
    json j;
    
    // add a number that is stored as double (note the implicit conversion of j to an object)
    j["pi"] = 3.141;
    
    // add a Boolean that is stored as bool
    j["happy"] = true;
    
    // add a string that is stored as std::string
    j["name"] = "Niels";
    
    // add another null object by passing nullptr
    j["nothing"] = nullptr;
    
    // add an object inside the object
    j["answer"]["everything"] = 42;
    
    // add an array that is stored as std::vector (using an initializer list)
    j["list"] = { 1, 0, 2 };
    
    // add another object (using an initializer list of pairs)
    j["object"] = { {"currency", "USD"}, {"value", 42.99} };
    
    // instead, you could also write (which looks very similar to the JSON above)
    json j2 = {
      {"pi", 3.141},
      {"happy", true},
      {"name", "Niels"},
      {"nothing", nullptr},
      {"answer", {
        {"everything", 42}
      }},
      {"list", {1, 0, 2}},
      {"object", {
        {"currency", "USD"},
        {"value", 42.99}
      }}
    };
    

    serialization

    // create object from string literal
    json j = "{ "happy": true, "pi": 3.141 }"_json;
    
    // or even nicer with a raw string literal
    auto j2 = R"(
      {
        "happy": true,
        "pi": 3.141
      }
    )"_json;
    
    // parse explicitly
    auto j3 = json::parse("{ "happy": true, "pi": 3.141 }");
    
    
    // explicit conversion to string
    std::string s = j.dump();    // {"happy":true,"pi":3.141}
    
    // serialization with pretty printing
    // pass in the amount of spaces to indent
    std::cout << j.dump(4) << std::endl;
    // {
    //     "happy": true,
    //     "pi": 3.141
    // }
    

    read from file/save to file

    // read a JSON file
    std::ifstream i("file.json");
    json j;
    i >> j;
    
    // write prettified JSON to another file
    std::ofstream o("pretty.json");
    o << std::setw(4) << j << std::endl;
    

    Arbitrary types conversions

    namespace ns {
        // a simple struct to model a person
        struct person {
            std::string name;
            std::string address;
            int age;
        };
    }
    

    normal method

    ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};
    
    // convert to JSON: copy each value into the JSON object
    json j;
    j["name"] = p.name;
    j["address"] = p.address;
    j["age"] = p.age;
    
    // ...
    
    // convert from JSON: copy each value from the JSON object
    ns::person p {
        j["name"].get<std::string>(),
        j["address"].get<std::string>(),
        j["age"].get<int>()
    };
    

    better method

    using nlohmann::json;
    
    namespace ns {
        void to_json(json& j, const person& p) {
            j = json{{"name", p.name}, {"address", p.address}, {"age", p.age}};
        }
    
        void from_json(const json& j, person& p) {
            j.at("name").get_to(p.name);
            j.at("address").get_to(p.address);
            j.at("age").get_to(p.age);
        }
    } // namespace ns
    
    
    // create a person
    ns::person p {"Ned Flanders", "744 Evergreen Terrace", 60};
    
    // conversion: person -> json
    json j = p;
    
    std::cout << j << std::endl;
    // {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"}
    
    // conversion: json -> person
    auto p2 = j.get<ns::person>();
    
    // that's it
    assert(p == p2);
    

    That's all! When calling the json constructor with your type, your custom to_json method will be automatically called. Likewise, when calling get<your_type>() or get_to(your_type&), the from_json method will be called.

    How do I convert third-party types?

    namespace nlohmann {
    
    template <typename T>
    struct adl_serializer {
        static void to_json(json& j, const T& value) {
            // calls the "to_json" method in T's namespace
        }
    
        static void from_json(const json& j, T& value) {
            // same thing, but with the "from_json" method
        }
    };
    
    }
    

    How can I use get() for non-default constructible/non-copyable types?

    struct move_only_type {
        move_only_type() = delete;
        move_only_type(int ii): i(ii) {}
        move_only_type(const move_only_type&) = delete;
        move_only_type(move_only_type&&) = default;
    
        int i;
    };
    
    namespace nlohmann {
        template <>
        struct adl_serializer<move_only_type> {
            // note: the return type is no longer 'void', and the method only takes
            // one argument
            static move_only_type from_json(const json& j) {
                return {j.get<int>()};
            }
    
            // Here's the catch! You must provide a to_json method! Otherwise you
            // will not be able to convert move_only_type to json, since you fully
            // specialized adl_serializer on that type
            static void to_json(json& j, move_only_type t) {
                j = t.i;
            }
        };
    }
    

    examples

    #pragma once
    
    #include <nlohmann/json.hpp>
    using json = nlohmann::json;
    #include "sensor_data.h"
    #include "rfid_info.h"
    
    namespace nlohmann {
    	template <>
    	struct adl_serializer<SensorData> {
    		// note: the return type is no longer 'void', and the method only takes
    		// one argument
    		static SensorData from_json(const json& j) {
    			SensorData sensor_data;
    			sensor_data.sensor_identify = j.at("SensorIdentify").get<string>();
    			return sensor_data;
    		}
    
    		// Here's the catch! You must provide a to_json method! Otherwise you
    		// will not be able to convert move_only_type to json, since you fully
    		// specialized adl_serializer on that type
    		static void to_json(json& j, SensorData t) {
    			j = json{ {"SensorIdentify",t.sensor_identify},{"SensorType",t.sensor_type },{"Data",t.data} };
    		}
    	};
    	template <>
    	struct adl_serializer<RfidInfo> {
    		// note: the return type is no longer 'void', and the method only takes
    		// one argument
    		static RfidInfo from_json(const json& j) {
    			RfidInfo rfid_info;
    			rfid_info.identify = j.at("Identify").get<string>();
    			return rfid_info;
    		}
    
    		// Here's the catch! You must provide a to_json method! Otherwise you
    		// will not be able to convert move_only_type to json, since you fully
    		// specialized adl_serializer on that type
    		static void to_json(json& j, RfidInfo t) {
    			j = json{ { "Identify",t.identify },{ "Position",0 } };
    		}
    	};
    }
    

    Binary formats(BSON...)

    // create a JSON value
    json j = R"({"compact": true, "schema": 0})"_json;
    
    // serialize to BSON
    std::vector<std::uint8_t> v_bson = json::to_bson(j);
    
    // 0x1B, 0x00, 0x00, 0x00, 0x08, 0x63, 0x6F, ...
    
    // roundtrip
    json j_from_bson = json::from_bson(v_bson);
    

    Reference

    History

    • 20191012: created.

    Copyright

  • 相关阅读:
    防删没什么意思啊,直接写废你~
    绝大多数情况下,没有解决不了的问题,只有因为平时缺少练习而惧怕问题的复杂度,畏惧的心理让我们选择避让,采取并不那么好的方案去解决问题
    Java 模拟面试题
    Crossthread operation not valid: Control 'progressBar1' accessed from a thread other than the thread it was created on
    一步步从数据库备份恢复SharePoint Portal Server 2003
    【转】理解 JavaScript 闭包
    Just For Fun
    The database schema is too old to perform this operation in this SharePoint cluster. Please upgrade the database and...
    Hello World!
    使用filter筛选刚体碰撞
  • 原文地址:https://www.cnblogs.com/kezunlin/p/12058300.html
Copyright © 2011-2022 走看看