Bootstrap

c++也可以优雅的处理json编码——使用nlohmann::json

参考:简单的用法

项目地址: https://github.com/nlohmann/json

前一篇文章用的是json-c,使用起来还算凑合,但是绝对的不能算是优雅,尤其是跟脚本语言相比。

很多时候我们希望能够封装类,优雅的实现JSON 的转换,我也是在阅读violetMiner源码时候发现人家用的是啥。(读代码是个好习惯),

1)首先看一下效果:

class address {
public:
	std::string street;
	int housenumber;
	int postcode;

public:
    // 类名,成员1,成员2,成员3
	NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode)

};

void test4()
{
	address addr{"robin's house", 12456, 100091};
	json jsonAddr = addr;
	cout << jsonAddr.dump() << endl;
}

看看,对于简单的类,使用了一个宏就搞定了;那么如果不用宏大概是个啥子样子呢?

2)使用普通的JSON库,大概都是这个样子滴

// 结构体的转换
struct person {
	std::string name;
	std::string address;
	int age;
};

// 比较传统的转换方法,大多json库都是类似
void test1()
{
	person p = { "Ned Flanders", "744 Evergreen Terrace", 60 };

	json j;
	j["name"] = p.name;
	j["address"] = p.address;
	j["age"] = p.age;

	string str = j.dump();

	person user1 = person{
	j["name"].get<std::string>(),
	j["address"].get<std::string>(),
	j["age"].get<int>()
	};
}
///

3)但是nlohmann::json还可以自己定义下转换过程:

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);
}

void test2()
{
	person p{ "Ned Flanders", "744 Evergreen Terrace", 60 };

	// conversion: person -> json
	json j = p;

	std::cout << j << std::endl;

	auto p2 = j.get<person>();
	//cout << p2;

}

这2个转换函数就是其中的关键,而在上文中看到的宏就是自动展开为这两个函数;

 

3)到这里,其实还有一个重要的问题我们没有提及,那就是万一JSON格式不对怎么办,比如我遇到的服务器返回的字符串缺少某个字段,我们需要异常处理,像这样:

// 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";

    //j["sex"] = "male";
	j.erase("sex");  // 删除不存在的值,无异常
	try
	{
		// test does not exist
		//string sex = j["sex"];
		string sex;
		sex = j.at("sex");
	
		cout << sex << endl;
	}
	catch (json::exception& e)
	{
		// output exception information
		std::cout << "message: " << e.what() << '\n'
			<< "exception id: " << e.id << std::endl;
	}
	

4) 最后在看一下,怎么像脚本语言一样处理JSON:

void initSetJson()
{
	json j2 = {
		{"pi", 3.141},
		{"happy", true},
		{"name", "Niels"},
		{"nothing", nullptr},
		{"answer", { {"everything", 42} } },
		{"list", {1, 0, 2} },
		{"object", {
		  {"currency", "USD"},
		  {"value", 42.99}
		}}
	};

	string message = j2.dump();

	cout << message << endl;

}

是不是挺惊艳?

回头再测试一下与json-c相比哪个快?

;