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

我想分配給嵌套的QVariantMap中的QVariant。第一個qDebug()不輸出,但第二個輸出「asdf」如預期的那樣。我如何將嵌套變量映射中的「bar」鍵分配給一個值?分配嵌套QVariantMap

回答

11

問題是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的使用。

+0

對於到達這裏在2016年讀者:使用Qt 5.1+和C++編譯器11這段代碼可以由更簡單,如[我的回答如下(http://stackoverflow.com/指出,問題/ 11090846 /分配到嵌套qvariantmap/37119292#37119292)。 –

2

或者你可以這樣做的方式,手推車不喜歡。

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

當qvariant_cast被執行時,對象被複制。你應該使用對象的指針。你可以嘗試下面的代碼而不是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"); 
} 

使用它作爲

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

越來越深

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

Starting from Qt 5.1,您可以使用C++11 uniform initialization syntax建立一個嵌套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" 
+0

我應該注意這種方法的明顯警告:只有當地圖上有一組已知的鍵時,它纔有效。 –