分配给嵌套的QVariantMap

11
#include <QtCore/QCoreApplication>
#include <QVariant>
#include <QtDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QVariantMap map;
    map["foo"] = QVariant(QVariantMap());
    map["baz"] = "asdf";
    qvariant_cast<QVariantMap>(map["foo"])["bar"] = "a";

    qDebug() << qvariant_cast<QVariantMap>(map["foo"])["bar"].toString();
    qDebug() << map["baz"].toString();

    return a.exec();
}

我正在尝试在嵌套的QVariantMap中进行赋值操作。第一个QDebug()没有输出任何内容,但第二个QDebug()按预期输出了"asdf"。我该如何将嵌套变量映射中的"bar"键分配给一个值?

5个回答

12
问题在于qvariant_cast没有返回对其操作的QVariant内部的引用,而是返回一个副本。因此,如果您用新的子映射覆盖顶级映射中的“foo”元素,则代码将正常工作:
#include <QtCore/QCoreApplication>
#include <QVariant>
#include <QtDebug>

int main(int argc, char** argv)
{
    QCoreApplication a(argc, argv);
    QVariantMap map;
    map["foo"] = QVariant(QVariantMap());
    map["baz"] = "asdf";

    QVariantMap newMap;
    newMap["bar"] = "a";
    map["foo"] = QVariant(newMap);

    qDebug() << qvariant_cast<QVariantMap>(map["foo"])["bar"].toString();
    qDebug() << map["baz"].toString();

    return a.exec();
}

可能你希望修改现有的地图而不是覆盖它。你可以通过复制现有的地图,添加新数据(这将导致深层复制),然后将地图写回来来实现这一目标:

QVariantMap existingMap = qvariant_cast<QVariantMap>(map["foo"]);
existingMap["bar"] = "a";
map["foo"] = QVariant(existingMap);

如果你正在考虑存储大量的数据,你可能需要重新考虑使用QVariant。


对于在2016年到达此处的读者:使用Qt 5.1+和C++11编译器,可以使这段代码变得更简单,如下面我的回答所指出的。 - Vicky Chijwani

3
或者您可以用那些推车不喜欢的方式来做。
#include <QtCore/QCoreApplication>
#include <QVariant>
#include <QtDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QVariantMap map;
    map["foo"] = QVariant(QVariantMap());
    map["baz"] = "asdf";
    static_cast<QVariantMap>(map["foo"].data_ptr())["bar"] = "a";

    qDebug() << qvariant_cast<QVariantMap>(map["foo"])["bar"].toString();
    qDebug() << map["baz"].toString();

    return a.exec();
}

或者您可以安全而稳妥地使用QExplicitlySharedDataPointer而不是直接使用QVariantMap。就像这样:

#include <QtCore>
#include <QtDebug>
class VarMap : public QVariantMap, public QSharedData {};
typedef QExplicitlySharedDataPointer<VarMap> SharedVarMap;
Q_DECLARE_METATYPE(SharedVarMap)
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QVariantMap map;
    map["foo"] = SharedVarMap(new VarMap());
    map["baz"] = "asdf";
    map["foo"].value<SharedVarMap>()->["bar"] = "a";

    qDebug() << map["foo"].value<SharedVarMap>()->["bar"].toString();
    qDebug() << map["baz"].toString();

    return a.exec();
}

2
template <typename T>
inline T& getStoredValueRef(QVariant &v)
{
    const auto type = qMetaTypeId<T>(static_cast<T*>(nullptr));
    auto& d = v.data_ptr();
    if (type == d.type)
    {
        auto data = reinterpret_cast<T*>(d.is_shared ? d.data.shared->ptr : &d.data.ptr);
        return *data;
    }
    throw std::runtime_error("Bad type");
}

将其用作

(getStoredValueRef<QVariantMap>(map["foo"]))["bar"] = "a";

更加深入

(getStoredValueRef<QVariantMap>(
    (getStoredValueRef<QVariantMap>(map["foo"]))["bar"]))["zoo"] = "a";

2

执行qvariant_cast时,对象被复制。你应该使用对象的指针。你可以尝试以下代码来替换qvariant_cast代码。

QVariantMap* m = (QVariantMap*)(map["foo"].data());
(*m)["bar"] = "a";

1

从Qt 5.1开始,您可以使用C++11统一初始化语法轻松构建嵌套的QMapQVariantMap(链接1) (链接2)

QVariantMap fooMap{
    {"bar", "a"}
};

QVariantMap map{
    {"foo", fooMap},   // nested map
    {"baz", "asdf"}
};

qDebug() << qvariant_cast<QVariantMap>(map["foo"])["bar"].toString();  // outputs "a"
qDebug() << map["baz"].toString();    // outputs "asdf"

我应该注意这种方法的明显警告:它仅在地图具有已知键集时才有效。 - Vicky Chijwani

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接