分配到嵌套QVariantMap(Assigning to nested QVariantMap)

2019-06-25 14:01发布

#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内分配到的QVariant。 第一qDebug()什么也不输出,但如预期的第二输出“ASDF”。 我将如何分配在嵌套变量映射到一个值“栏中的”钥匙?

Answer 1:

问题是,qvariant_cast不会返回到它在操作的QVariant的内部参考; 它返回一个副本。 因此,如果你在覆盖用新的子图顶层图的“福”元素,代码将正常工作:

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

据推测,要修改现有的地图,而不是overwritting它。 您可以通过复制现有地图做到这一点,添加新的数据(这将导致在深副本),然后写在地图回来:

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

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



Answer 2:

或者你可以做到这一点trollies不喜欢的方式。

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


Answer 3:

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


Answer 4:

当执行qvariant_cast,对象被复制。 你应该使用对象的指针。 你可以试试下面的代码,而不是qvariant_cast代码。

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


Answer 5:

从Qt的5.1开始 ,你可以使用C ++ 11统一初始化语法来构建一个嵌套QMapQVariantMap容易:

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"


文章来源: Assigning to nested QVariantMap