初めに
t["user"]["name"] = "K10-K10";
t["user"]["age"] = 15;
std::cout << t["user"]["name"] << std::endl;//K10-K10
のような階層構造を実装したい。
コード
#include <iostream>
#include <map>
#include <string>
#include <variant>
class Json {
public:
using object = std::map<std::string, Json>;
using value = std::variant<std::string, object>;
value data = object{};
class Proxy {
Json& ref;
public:
Proxy(Json& r) : ref(r) {}
Proxy operator[](const std::string& key) {//階層化
if (!std::holds_alternative<object>(ref.data)) {
ref.data = object{};
}
auto& obj = std::get<object>(ref.data);
return Proxy(obj[key]); // key がなければ生成される
}
Proxy& operator=(const std::string& v) {//代入
ref.data = v;
return *this;
}
Proxy& operator=(int v) {//代入(int)
ref.data = std::to_string(v);
return *this;
}
operator std::string() const {
if (std::holds_alternative<std::string>(ref.data)) {
return std::get<std::string>(ref.data);
}
return "[object]";
}
};
Proxy operator[](const std::string& key) {
return Proxy(*this)[key];
}
};
使い方
int main() {
Json t;
t["user"]["name"] = "K10-K10";
t["user"]["age"] = 15;
std::cout << t["user"]["name"] << std::endl;//K10-K10
std::cout << t["user"]["age"] << std::endl;//15
return 0;
}
解説
dataがツリー構造になっている。
std::variant<std::string, std::map<std::string, Json>>
Jsonクラス
Jsonは1ノードを指す。
class Json {
public:
using object = std::map<std::string, Json>;
using value = std::string;
std::variant<value, object> data;
Json() : data(object{}) {}
};
| JSON | C++ 側 |
|---|---|
"hello" |
Json{ std::string("hello") } |
{} |
Json{ map{} } |
{ "a": 1 } |
Json{ map{ "a" → Json{"1"} } } |
階層化
t["user"]["name"] = "K10-K10"は
t.data
└── map
└── "user" : Json
└── map
└── "name" : Json
└── string "K10-K10"
{
"user": {
"name": "K10-K10"
}
}
t["user"]["age"] = 15を追加すると
t.data
└── map
└── "user" : Json
└── map
├── "name" : Json
│ └── "K10-K10"
└── "age" : Json
└── "15"
{
"user": {
"name": "K10-K10",
"age": "15"
}
}
上のコードは
t["user"]
Proxy p1 = t.operator[]("user");
["name"]
Proxy p2 = p1.operator[]("name");
= "K10-K10
Proxy& Proxy::operator=(const std::string& value) {
ref.data = value;
return *this;
}
のような流れで動作している。