如何在 QJsonArray 中使用基于 C++11 的范围

Pau*_*one 9 qt for-loop c++11

使用旧式循环,我可以深入研究 aQJsonArray并在下面的示例中为每个数组项添加元素“foo”和现有元素“bar”的内容。我如何使用基于 C++11 的范围来做到这一点?

// QJsonArray oldArray contains an array of which one element is "bar"
QJsonArray newArray;
int i, b = oldArray.count();
for (i=0; i<n; ++i) {
    QJsonObject element = oldArray.at(i).toObject();
    element["foo"] = element["bar"];
    newArray.append(element);
}
Run Code Online (Sandbox Code Playgroud)

我尝试了以下方法(无可否认是反复试验):

汽车&

for (auto& element : oldArray) {
    element["foo"] = element["bar];
    newArray.append(element);
}
Run Code Online (Sandbox Code Playgroud)

我收到错误

对类型“QJsonValueRef”的非常量左值引用无法绑定到“QJsonValueRef”类型的临时变量

常量自动&

for (const auto& element : oldArray) {
...
Run Code Online (Sandbox Code Playgroud)

我收到警告

循环变量“元素”始终是副本,因为“QJsonArray”类型的范围不返回引用

常量自动

for (const auto element : oldArray) {
    element["foo"] = element["bar];
    ...
Run Code Online (Sandbox Code Playgroud)

我收到错误

'const QJsonValueRef' 类型没有可行的重载运算符 []

关系到 element["bar"]

Pau*_*one 8

问题是迭代器 forQJsonArray返回一个临时QJsonValueRef对象,而左值引用不能绑定到临时对象。我们可以按值持有该临时文件:

// QJsonArray oldArray contains an array of which one element is "bar"
QJsonArray newArray;
for (auto v : oldArray) {
    QJsonObject element = v.toObject();
    element["foo"] = element["bar"];
    newArray.append(element);
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下v是一个QJsonValueRef对象(类似于oldArray.at(i)旧式循环中给出的内容)。之后,我们将其转换QJsonValueRefQJsonObjectusing .toObject()

或者我们可以使用转发引用,因为它们可以绑定到右值:

for (auto&& v : oldArray) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,v被推导为对 a 的右值引用QJsonValueRef

两种解决方案在创建/销毁的对象数量方面是相同的(因为在前者中,在使用任何体面的编译器时,副本在C++17 保证复制省略规则下甚至在 C++17 之前的版本中被省略。在后者,引用绑定到临时对象,这会延长其生命周期以匹配整个迭代)。


笔记

  1. 这个问题类似于使用 range-based-for 和 astd::vector<bool>时发生的情况。因为两者std::vector<bool>QJsonArray有返回的代理对象的迭代器。
  2. 如果使用 Clang 代码模型,则第二个解决方案会生成警告“循环变量 'v' 始终是副本,因为类型 'QJsonArray' 的范围不返回引用”。请参阅此问题以获取解释。