nlohmann/json

シリアライゼーションC++JSONヘッダーオンリーModern C++型安全

ライブラリ

nlohmann/json

概要

nlohmann/jsonは、モダンC++向けに設計された最も人気のあるJSONライブラリです。JSONデータをC++の第一級市民として扱うことを目指し、直感的なAPIと豊富な機能を提供します。単一のヘッダーファイルをインクルードするだけで使用でき、STLコンテナのような使い心地でJSONを操作できます。型安全性と使いやすさを重視した設計により、C++プロジェクトでのJSON処理のデファクトスタンダードとなっています。

詳細

nlohmann/jsonは、C++11以降の機能を活用して開発された、ヘッダーオンリーのJSONライブラリです。JSONの全機能(オブジェクト、配列、文字列、数値、ブール値、null)をサポートし、自動型推論、カスタム型のシリアライゼーション、SAX/DOMスタイルのパース、JSONポインター、JSONパッチなどの高度な機能も提供します。設計哲学は「使いやすさファースト」で、C++プログラマーが直感的に使えるインターフェースを提供します。

主な特徴

  • ヘッダーオンリー: 単一ファイルで完結し、ビルド設定が不要
  • STLライク: vectorやmapのような直感的な操作感
  • 型安全性: C++の型システムと深く統合
  • 豊富な機能: JSONポインター、JSONパッチ、MessagePack/CBOR/UBJSON対応
  • カスタマイズ可能: ユーザー定義型の自動シリアライゼーション
  • 例外安全: 強い例外保証を提供

メリット・デメリット

メリット

  • 極めて直感的で使いやすいAPI設計
  • 単一ヘッダーファイルで導入が簡単
  • 豊富なドキュメントとコミュニティサポート
  • カスタム型の自動シリアライゼーション機能
  • UTF-8完全対応で国際化に強い
  • アクティブな開発とメンテナンス

デメリット

  • パフォーマンスは他のC++ JSONライブラリより劣る
  • ファイルサイズが大きい(約1MB)
  • コンパイル時間が長くなる可能性
  • C++11以降が必須
  • メモリ使用量が比較的多い
  • 巨大なJSONファイルの処理には不向き

参考ページ

書き方の例

基本的な使用方法

#include <nlohmann/json.hpp>
#include <iostream>

using json = nlohmann::json;

int main() {
    // JSONオブジェクトの作成
    json j = {
        {"name", "John Doe"},
        {"age", 30},
        {"city", "Tokyo"},
        {"is_active", true},
        {"scores", {85, 90, 78}}
    };
    
    // シリアライズ(整形出力)
    std::cout << j.dump(4) << std::endl;
    
    // 要素へのアクセス
    std::string name = j["name"];
    int age = j["age"].get<int>();
    
    return 0;
}

パースとエラーハンドリング

#include <nlohmann/json.hpp>
#include <fstream>

using json = nlohmann::json;

void parseJsonFile(const std::string& filename) {
    try {
        // ファイルから読み込み
        std::ifstream file(filename);
        json j;
        file >> j;
        
        // 安全な要素アクセス
        if (j.contains("users")) {
            for (auto& user : j["users"]) {
                std::cout << user.at("name") << std::endl;
            }
        }
    } catch (json::parse_error& e) {
        std::cerr << "Parse error: " << e.what() << std::endl;
    } catch (json::out_of_range& e) {
        std::cerr << "Key not found: " << e.what() << std::endl;
    }
}

カスタム型のシリアライゼーション

#include <nlohmann/json.hpp>

struct Person {
    std::string name;
    int age;
    std::string email;
};

// マクロを使用した自動シリアライゼーション
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Person, name, age, email)

int main() {
    // カスタム型の使用
    Person p{"Alice", 25, "[email protected]"};
    
    // 自動的にJSONに変換
    json j = p;
    std::cout << j.dump(2) << std::endl;
    
    // JSONからカスタム型へ
    json j2 = {{"name", "Bob"}, {"age", 30}, {"email", "[email protected]"}};
    Person p2 = j2.get<Person>();
    
    return 0;
}

高度な機能の使用

#include <nlohmann/json.hpp>

using json = nlohmann::json;

void advancedFeatures() {
    json j = {
        {"users", {
            {{"name", "John"}, {"age", 30}},
            {{"name", "Jane"}, {"age", 25}}
        }}
    };
    
    // JSONポインター
    auto name = j[json::json_pointer("/users/0/name")];
    
    // JSONパッチ
    json patch = {{
        {"op", "replace"},
        {"path", "/users/0/age"},
        {"value", 31}
    }};
    j = j.patch(patch);
    
    // イテレーション
    for (auto& [key, value] : j.items()) {
        std::cout << key << ": " << value << std::endl;
    }
    
    // MessagePack変換
    std::vector<uint8_t> msgpack = json::to_msgpack(j);
    json j_from_msgpack = json::from_msgpack(msgpack);
}

SAXスタイルのパース

#include <nlohmann/json.hpp>

class MySaxHandler {
public:
    bool null() { return true; }
    bool boolean(bool val) { return true; }
    bool number_integer(int64_t val) { return true; }
    bool number_unsigned(uint64_t val) { return true; }
    bool number_float(double val, const std::string& s) { return true; }
    bool string(std::string& val) { return true; }
    bool start_object(std::size_t elements) { return true; }
    bool end_object() { return true; }
    bool start_array(std::size_t elements) { return true; }
    bool end_array() { return true; }
    bool key(std::string& val) { return true; }
    bool parse_error(std::size_t position, const std::string& last_token) { return false; }
};

void saxParsing() {
    std::string json_str = R"({"name": "John", "age": 30})";
    MySaxHandler handler;
    json::sax_parse(json_str, &handler);
}

設定ファイルの読み書き

#include <nlohmann/json.hpp>
#include <fstream>

class Config {
    json config_;
    std::string filename_;
    
public:
    Config(const std::string& filename) : filename_(filename) {
        load();
    }
    
    void load() {
        try {
            std::ifstream file(filename_);
            if (file.is_open()) {
                file >> config_;
            }
        } catch (...) {
            config_ = json::object();
        }
    }
    
    void save() {
        std::ofstream file(filename_);
        file << config_.dump(4);
    }
    
    template<typename T>
    T get(const std::string& key, const T& default_value) {
        return config_.value(key, default_value);
    }
    
    template<typename T>
    void set(const std::string& key, const T& value) {
        config_[key] = value;
    }
};