nlohmann/json
ライブラリ
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;
}
};