我正在查看nlohmann json库,我看到作者可以像这样构造json对象:
json j2 = {
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
{"nothing", nullptr},
{"answer", {
{"everything", 42}
}},
{"list", {1, 0, 2}},
{"object", {
{"currency", "USD"},
{"value", 42.99}
}}
};
下面的例子中,他说:
请注意,在所有这些情况下,您永远不需要“告诉”编译器您想要使用哪个JSON值类型。如果你想明确或表达一些边缘情况,函数json::array()和json::object()会有所帮助:
我对此很感兴趣,并尝试实现我自己的这种行为的简化版本,但我没有成功。我在让初始化器列表同时接受不同类型时遇到了麻烦。我也试着分析了nlohmann库的实际源代码,我看到他的json对象也有一个构造函数,它接受一个std::initializer_list
,这个std::initializer_list
包含一些(据我所知)固定类型,但我不明白这是如何让std::initializer_list
理解像例子中那样的嵌套的花括号初始化列表的。
判断初始化器列表是表示JSONArray
还是JSONMap
的条件应该如下:
如果列表中的每个嵌套元素本身都是一个长度为2的数组,其中第一个元素的类型可以用于构造JSONString
。(我在考虑使用类似std::is_constructible_v<JSONString, T>
的东西),而第二个元素是可以用来构造JSONObject
的东西,那么我们可以推断出整个初始化器列表表示一个JSONMap
,否则我们将其视为JSONAarray
最后,我想以这样的代码结束:
#include <iostream>
#include <vector>
#include <map>
#include <variant>
class JSONObject;
using JSONString = std::string;
using JSONNumber = double;
using JSONBool = bool;
using JSONNull = nullptr_t;
using JSONArray = std::vector<JSONObject>;
using JSONMap = std::map<std::string, JSONObject>;
class JSONObject {
public:
JSONObject() : var{JSONMap{}} {}
template <typename T>
JSONObject(std::initializer_list<T> list) {
// I do not understand how to implement this
}
private:
std::variant<JSONString, JSONNumber, JSONBool, JSONNull, JSONArray, JSONMap> var;
};
int main() {
JSONObject jsonObj = {
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
{"nothing", nullptr},
{"answer", {
{"everything", 42}
}},
{"list", {1, 0, 2}},
{"object", {
{"currency", "USD"},
{"value", 42.99}
}}
};
return 0;
}
在做一些研究的时候,我也有了一个想法,为JSONObject
做一个可变模板构造器,如下所示:
template <typename... Args>
JSONObject(Args&&... args) {
// some fold expression to deduce how to construct the variant
}
但即使这样,我在处理嵌套的花括号初始化列表时还是遇到了麻烦
1条答案
按热度按时间0tdrvxhp1#
std::initializer_list
在类型上是同质的--所有元素都是相同的类型。诀窍是创建一个可以保存不同值的单一类型。这就是std::variant
发挥作用的地方。使用
std::variant
的棘手之处在于它不是递归的,即它不能保存自己类型的值。有一些递归的变体实现,如rva::variant和Boost。另外,如果你想了解细节,here是一个关于如何实现递归变体类型的很好的教程。
更新
下面的代码是使用
rva::variant
作为json类型的粗略草图。原型允许使用自然的初始化语法,就像nlohmann
json一样。它使用相同的技术来区分对象和数组。示例代码
输出