2012-06-18 16 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(); 
} 

Sto tentando di assegnare a QVariant all'interno di una QVariantMap nidificata. Il primo qDebug() non emette nulla, ma il secondo emette "asdf" come previsto. Come potrei assegnare la chiave "bar" nella mappa variabile annidata ad un valore?Assegnazione alla QVariantMap nidificata

risposta

11

Il problema è che qvariant_cast non restituisce un riferimento ai interni del QVariant su cui sta operando; restituisce una copia. In quanto tale, se si sovrascrive l'elemento "foo" nella mappa di livello superiore con una nuova mappa del bambino, il codice funzionerà correttamente:

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

Presumibilmente, si desidera modificare la mappa esistente invece di overwritting esso. È possibile ottenere questo risultato copiando il mappa esistente, aggiungendo i nuovi dati (che si tradurrà in una copia di profondità), e poi scrivendo la mappa di nuovo in:

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

Se state pensando di memorizzare una grande quantità di dati , potresti voler riconsiderare l'uso di QVariant.

+0

Per i lettori che arrivano qui nel 2016: con Qt 5.1+ e un compilatore C++ 11 questo codice può essere reso molto più semplice, come sottolineato in [la mia risposta qui sotto] domande/11090846/assegnando-to-nested-qvariantmap/37119292 # 37119292). –

2

Oppure si potrebbe fare come i trolle non piacciono.

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

Oppure si potrebbe fare tutto sicuro e piacevole e utilizzare un QExplicitlySharedDataPointer anziché direttamente un QVariantMap. In questo modo:

#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

Quando qvariant_cast viene eseguito, l'oggetto viene copiato. dovresti usare un puntatore dell'oggetto. Puoi provare il seguente codice al posto del codice 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"); 
} 

usarlo come

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

e più profonda

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

Starting from Qt 5.1, è possibile utilizzare il C++11 uniform initialization syntax per costruire un nidificato QMap o QVariantMap facilmente:

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

Dovrei notare l'avvertimento evidente con questo approccio: funziona solo se la mappa ha un insieme noto di chiavi. –