我正在使用一个小型C++JSON库来帮助提高我生疏的C++技能,而且我在理解初始化列表的一些行为时遇到了困难。
库的核心是一个变量类(名为"var"),它存储各种JSON数据类型(null、boolean、number、string、object、array)中的任何一种。
var
的目标是与JavaScript变量尽可能紧密地工作,因此存在大量运算符重载。原始数据类型很容易处理。。。
var fee = "something";
var fie = 123.45;
var foe = false;
问题出在对象(贴图)和数组(向量)上。
为了获得接近JavaScript对象和数组文字语法的东西,我使用初始化列表。它看起来像这样:
// in my headers
typedef var object[][2];
typedef var array[];
// in user code
var foo = (array){ 1, "b", true };
var bar = (object){ { "name", "Bob" }, { "age", 42 } };
这个效果很好。这个问题来自于嵌套列表。
var foo = (array){ 1, "b", (array){ 3.1, 3.2 } };
出于某种原因,我的变体类将嵌套的"数组"解释为布尔值,给出:
[1, "b", true]
代替:
[1, "b", [3.1, 3.2]]
如果我显式地将内部列表强制转换为var,它会起作用:
var foo = (array){ 1, "b", (var)(array){ 3.1, 3.2 } };
为什么在将内部列表强制转换为数组后,必须将其显式强制转换为var,以及如何绕过这种额外的强制转换?据我所知,它应该隐式地将数组转换为我的var类,因为它使用的是vars数组的构造函数:
template <size_t length>
var(const var(&start)[length]) {
// internal stuff
init();
setFromArray(vector<var>(start, start + length));
}
似乎如果没有显式的var转换,初始化列表在从数组转换为var的过程中会以某种方式转换为其他内容。我正在努力理解为什么会发生这种情况,以及如何避免这种情况。
这是一个要点和完整的来源。让我知道我是否应该补充任何与这个问题相关的内容。
更新
显然,(foo){1, "two"}
实际上并没有抛出初始化列表;这是一个完整的表达式,称为复合文字。它似乎只在C中可用,尽管g++不会抱怨,除非你给它-pedantic
。
看起来我的选择是:
- 找到另一个官方支持的简明初始化语法
- 使用复合文字,并希望它们能在其他编译器中使用
- 放弃对C++的支持<11并使用initializer_list
- 不要提供简洁的初始化语法
第一个选项的任何帮助都将是我目前正在寻找的答案。
宏是另一种最后的选择,我已经写了一些可以完成这项工作的宏,但我不想使用它们。
您需要使用Boost已经为您提供的设施。
typedef boost::optional<boost::make_recursive_variant<
float, int, bool, //.. etc
std::unordered_map<std::string, boost::optional<boost::recursive_variant_>>,
std::vector<boost::recursive_variant_>
> JSONType;
它们可以很容易地定义递归变体类型。