Seite 1 von 1
QMap of QMaps
Verfasst: 26. März 2012 10:59
von conan2011
Ich bin eben so ratlos, wie dieses Thema bereits durchgekaut ist, bitte helft mir
Ich will eine QMap füllen, die eine weitere QMap enthält.
Folgender Code funktioniert (index sei gegeben):
Code: Alles auswählen
QMap<QModelIndex, QMap <int,QVariant> > myBuffer;
QMap <int, QVariant> newEntry;
newEntry.insert(1, QVariant("foo"));
myBuffer.insert(index, newEntry);
sobald ich jedoch die Definition von myBuffer in den Header der Klasse verfrachte (private), meldet der Compiler folgenden Fehler:
Code: Alles auswählen
passing 'const QMap<QModelIndex, QMap <int, QVariant> >' as 'this' argument of 'QMap<Key, T>::iterator QMap<Key, T>::insert(const Key&, const T&) [with Key = QModelIndex, T = QMap<int, QVariant>]' discards qualifiers
die Definition von myBuffer MUSS aber in den Header, hat jemand eine Lösung?
Und wie kommt der Compiler überhaupt auf "const QMap...", ich hab doch nirgends "const" geschrieben

Re: QMap of QMaps
Verfasst: 26. März 2012 11:23
von brax
conan2011 hat geschrieben:
Und wie kommt der Compiler überhaupt auf "const QMap...", ich hab doch nirgends "const" geschrieben

Bist Du Dir da sicher? Grundsätzlich fehlt hier relevanter Code. Also die Klassendefinition und die Methode aus der der von Dir gepostete Code stammt.
Hier etwas, was kompiliert:
mapTest.h:
Code: Alles auswählen
#ifndef MAP_TEST_H
#define MAP_TEST_H
#include <QMap>
#include <QModelIndex>
class MapTest {
public:
void insertTest(QModelIndex index);
private:
QMap<QModelIndex, QMap <int,QVariant> > myBuffer;
};
#endif
Und die mapTest.cpp:
Code: Alles auswählen
#include "mapTest.h"
//-----------------------------------------------------------------------------
void MapTest::insertTest(QModelIndex index) {
QMap<int, QVariant> newEntry;
newEntry.insert(1, QVariant("foo"));
myBuffer.insert(index, newEntry);
}
Das gibt keinen Fehler, also scheinst Du doch irgendwo etwas Code zu haben, den Du nicht gepostet hast und der dafür sorgt, dass es bei Dir einen Fehler gibt (meine Vermutung: Die Methode, die ich "insertTest" genannt habe, ist bei Dir const?)
Re: QMap of QMaps
Verfasst: 26. März 2012 11:49
von conan2011
Vielen Dank für die Mühe, die du dir gemacht hast.
Und du hast Recht, der Code steht in der data-Funktion meines QAbstractItemModels, und die ist 'const':
Code: Alles auswählen
QVariant myModel::data(const QModelIndex &index, int role) const
Das heißt es ist schier unmöglich, aus der "data() const"-Funktion heraus meine Klassenvariable zu verändern. Hmmm, 'const' einfach weglassen geht natürlich auch nicht.
Ich MUSS aber in der data-Funktion irgendwie meinen Buffer füllen.
Vielleicht hier noch eine Idee?
Re: QMap of QMaps
Verfasst: 26. März 2012 12:03
von brax
Was Du Dich wohl fragen solltest ist, warum ist die data Methode const? Und (die eigentliche Frage), warum soll in der als const deklarierten Methode das this Objekt verändert werden (was Du ja tun möchtest, indem Du myBuffer verändern möchtest)? Grundsätzlich ist ja die Deklaration als const ein Hinweis, dass in dieser Methode das Objekt nicht verändert wird.
Die Antwort wird wohl lauten: weil Du eine Methode überschreibst, die const ist, richtig? Ich bin mir nicht sicher wie Dein Anwendungsfall ist, aber ich interpretiere das jetzt mal so, dass myBuffer quasi ein Cache ist. Nun könnte man argumentieren, dass durch die Änderung eines Caches die wesentlichen Eigenschaften Deines Objektes nicht wirklich verändert werden, wodurch ein Bruch der const-correctness zu vertreten wäre (man müsste dann natürlich sicher stellen, dass dieser "Cache" entsprechend invalidiert wird etc.). So richtig schön sauber ist es aber auf jeden Fall nicht, und manch einer würde Dir ganz doll auf die Finder hauen, wenn Du const-correctness ignorierst (mehr Informationen zu const-correctness und ein paar Gedanken, warum es eine feine Sache ist, darauf zu achten, findest Du hier:
http://www.parashift.com/c++-faq-lite/c ... tness.html).
So oder so, es gibt nun zwei wege, wie Du trotz des const-qualifiers der data Methode Deinen Buffer verändern kannst:
1. const_cast
Code: Alles auswählen
QVariant myModel::data(const QModelIndex &index, int role) const {
myModel* mutableThis = const_cast<myModel*>(this); // macht aus const myModel* ein myModel*
mutableThis->myBuffer->insert(....);
....
}
2. myBuffer mutable deklarieren.
Code: Alles auswählen
class myModel : public QAbstractItemModel {
...
private:
mutable QMap<QModelIndex, QMap <int,QVariant> > myBuffer; // das Schlüsselwort "mutable" bedeutet, dass dieser Member auch in const-Methoden verändert werden darf
};
Wie gesagt, die feine englische Art ist beides nicht gerade...
Re: QMap of QMaps
Verfasst: 26. März 2012 12:04
von franzf
Wieso willst du einen Buffer in der data()-Methode FÜLLEN? data() wird recht oft aufgerufen. Wenn du anfängst, da groß rumzupuffern, kann das ziemlich auf die Performance gehen.
Wenn du dir aber wirklich sicher bist, gibt es zwei Möglichkeiten:
1) const_cast
2) mutable
Ich überlass es dir, wobei das mutable-keyword genau für solche Sachen existiert.
Re: QMap of QMaps
Verfasst: 26. März 2012 12:32
von conan2011
Perfekt, es funktioniert, ihr glaubt gar nicht wie dankbar ich bin!
mutable und const_cast kannte ich gar nicht, und wieder was gelernt.
Und auf die Frage, WARUM ich das überhaupt vorhabe:
Die data-Funktion holt in meiner Implementation jeden Wert über eine ODBC-Connection aus der Datenbank. Bislang ging das auch ausreichend flott, aber wenn die QTableView dann etwas größer wird, und für jedes einzelne Feld Daten mit mehreren roles abgefragt werden, geht die Performance ziemlich runter.
Aufgefallen ist mir das, als ich mit einem eigenen Contextmenü auf das Ereignis CustomContextMenuRequestet reagiert habe. Hier fordert die View nämlich nochmal ALLE Daten für absolut JEDES Feld der Tableview an.
Ich weiß, ich habe hiermit das eigentilche Problem umgangen, nämlich das ContextMenü daran zu hindern, einen kompletten Refresh der View anzuleiern, aber die Daten optional buffern zu können steht eh auf der ToDo-Liste.
Also, nochmal Vielen Dank!