2012-06-18 17 views
10
#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(); 
} 

Próbuję przypisać do QVariant w zagnieżdżonej QVariantMap. Pierwszy qDebug() nic nie daje, ale drugi wyprowadza "asdf" zgodnie z oczekiwaniami. Jak przypisać klucz "bar" w zagnieżdżonej mapie zmiennych do wartości?Przypisywanie zagnieżdżonej QVariantMap

Odpowiedz

11

Kwestia polega na tym, że qvariant_cast nie zwraca odwołania do elementów wewnętrznych QVariant, na którym działa; zwraca kopię. Jako takie, jeśli zastąpić „foo” element mapy najwyższego poziomu z nowym dzieckiem mapie, kod będzie działał poprawnie:

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

Przypuszczalnie chcesz zmodyfikować istniejącą mapę zamiast overwritting go. Można tego dokonać poprzez skopiowanie istniejącej mapy, dodając nowe dane (które wynikną w głębokiej kopii), a następnie pisemnie mapę z powrotem w:

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

Jeśli rozważasz przechowywania dużej ilości danych , możesz chcieć ponownie rozważyć wykorzystanie QVariant.

+0

Dla czytelników przybywających tutaj w 2016: z Qt 5.1+ i kompilatorem C++ 11 ten kod może być znacznie uproszczony, jak wskazano w [moja odpowiedź poniżej] (http://stackoverflow.com/ pytania/11090846/przypisywanie-do-zagnieżdżonych-qvariantmap/37119292 # 37119292). –

2

Albo możesz to zrobić tak, jak nie lubią trolle.

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

Albo można zrobić to wszystko jest bezpieczne i ładne i używać QExplicitlySharedDataPointer zamiast bezpośrednio do QVariantMap. W ten sposób:

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

Po wykonaniu qvariant_cast obiekt jest kopiowany. powinieneś użyć wskaźnika obiektu. Możesz wypróbować poniższy kod zamiast kodu qvariant_cast.

QVariantMap* m = (QVariantMap*)(map["foo"].data()); 
(*m)["bar"] = "a"; 
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"); 
} 

używać go jako

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

i bardziej głęboko

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

Starting from Qt 5.1, można użyć C++11 uniform initialization syntax budować zagnieżdżone QMap lub QVariantMap prościej:

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" 
+0

Należy zauważyć oczywiste zastrzeżenie w tym podejściu: działa tylko wtedy, gdy mapa ma znany zestaw kluczy. –