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

Estoy tratando de asignar un QVariant dentro de un QVariantMap anidado. El primer qDebug() no genera nada, pero el segundo da como resultado "asdf". ¿Cómo asignaría la clave "barra" en el mapa de variables anidadas a un valor?Asignación a QVariantMap anidado

Respuesta

11

El problema es que qvariant_cast no devuelve una referencia a las partes internas de QVariant en las que está operando; devuelve una copia. Como tal, si sobrescribe el elemento "foo" en su mapa de nivel superior con un nuevo mapa niño, el código funcionará correctamente:

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

Es de suponer, que desea modificar el mapa existente en lugar de overwritting ella. Esto se puede hacer mediante la copia del mapa existente, añadiendo los nuevos datos (que dará lugar a una copia en profundidad), y luego escribir el mapa de vuelta en:

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

Si usted está considerando el almacenamiento de una gran cantidad de datos , es posible que desee reconsiderar su uso de QVariant.

+0

Para los lectores que lleguen aquí en 2016: con Qt 5.1+ y un compilador C++ 11, este código puede simplificarse mucho, como se señala en [mi respuesta a continuación] (http://stackoverflow.com/ preguntas/11090846/assigning-to-nested-qvariantmap/37119292 # 37119292). –

2

O podría hacerlo de la manera que no le gusta a los carritos.

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

O puede hacerlo todo seguro y agradable y utilizar un QExplicitlySharedDataPointer en lugar de directamente un QVariantMap. De esta manera:

#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

Cuando se ejecuta qvariant_cast, el objeto se copia. deberías usar un puntero del objeto. Puede probar el siguiente código en lugar del código 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"); 
} 

utilizarlo como

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

y más profunda

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

Starting from Qt 5.1, se puede utilizar el C++11 uniform initialization syntax para construir un anidado QMap o QVariantMap fácilmente:

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

Debo señalar la advertencia obvia con este enfoque: solo funciona si el mapa tiene un conjunto conocido de claves. –