Назначение вложенному QVariantMap
#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();
}
Я пытаюсь назначить QVariant внутри вложенного QVariantMap. Первый qDebug () ничего не выводит, но второй выводит "asdf", как и ожидалось. Как назначить ключ "bar"во вложенной переменной map значению?
5 ответов
проблема в том, что 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.
или вы можете сделать это так, как тролли не любят.
#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();
}
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";
при выполнении qvariant_cast копируется объект. вы должны использовать указатель на объект. Вы можете попробовать следующий код вместо кода qvariant_cast.
QVariantMap* m = (QVariantMap*)(map["foo"].data());
(*m)["bar"] = "a";
начиная с Qt 5.1 можно использовать в C++11 инициализации синтаксис построить вложенные QMap
или QVariantMap
легко:
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"