Wie Vergleiche für QVariant Objekte zu unterstützen, einen benutzerdefinierten Typ enthalten?

StackOverflow https://stackoverflow.com/questions/2868673

  •  01-10-2019
  •  | 
  •  

Frage

Nach der Qt-Dokumentation, QVariant::operator== funktioniert nicht wie man erwarten könnte, wenn die Variante einen benutzerdefinierten Typ enthält:

  

bool QVariant :: operator == (const QVariant & v) const

     

Vergleicht diesen QVariant mit v und   wenn sie zurückkehrt wahr gleich sind;   andernfalls wird false zurückgegeben.

     

Im Fall von benutzerdefinierten Typen, ihre   Ebenbürtigkeit Operatoren werden nicht genannt.   Statt die Adressen der Werte   verglichen.

Wie soll man erhält diese für die benutzerdefinierten Typen sinnvoll zu verhalten? In meinem Fall, ich bin Speicher einen aufgezählten Wert in einem QVariant, z.

In einem Header:

enum MyEnum { Foo, Bar };

Q_DECLARE_METATYPE(MyEnum);

Irgendwo in einer Funktion:

QVariant var1 = QVariant::fromValue<MyEnum>(Foo);
QVariant var2 = QVariant::fromValue<MyEnum>(Foo);
assert(var1 == var2); // Fails!

Was brauche ich für diese Behauptung anders zu tun, um wahr zu sein?

Ich verstehe Warum es funktioniert nicht - jede Variante wird eine separate Kopie der aufgezählten Wert zu speichern, so dass sie unterschiedliche Adressen haben. Ich möchte wissen, wie ich meine Vorgehensweise ändern kann diese Werte in Varianten so zu speichern, dass entweder dies kein Problem ist, oder so, dass sie den gleichen zugrunde liegenden Variable beide Referenz tun.

Es glaube nicht, es möglich ist, für mich Gleichheitsvergleiche zu arbeiten, um zu umgehen. Der Kontext ist, dass ich in einem Artikel in QComboBox diese Aufzählung als Userdata verwenden, und ich möchte in der Lage seinen QComboBox::findData zu verwenden, um den Artikel Index zu einem bestimmten Aufzählungswert entspricht, ausfindig zu machen.

War es hilfreich?

Lösung

Die offensichtliche Antwort ist, die Daten aus mit var1.value<MyEnum>() == var2.value<MyEnum>() zu werfen, sie zu vergleichen, aber das erfordert, dass Sie die Art wissen, wann zu vergleichen. Es scheint, wie in Ihrem Fall dies möglich sein könnte.

Wenn Sie nur Aufzählungen verwenden, könnten Sie es auch für die Speicherung im QVariant in einen int umwandeln.

Edit: Zur Klarstellung über die Suche eines QComboBox , verwendet das Modell der Combo-Box die Daten zu finden, . Insbesondere verwendet es die match() Funktion der QAbstractItemModel für Gleichheit zu überprüfen. Glücklicherweise ist diese Funktion virtuell, so dass Sie es in einer Unterklasse außer Kraft setzen können.

Andere Tipps

Versuchen Hack QVariant, definieren die Funktion von Prototyp

typedef bool (*f_compare)(const Private *, const Private *);

und setzen Sie ihn auf QVariant Handler; Um die Arbeit mit QVariant qt Verwendung Handler:

struct Handler {
    f_construct construct;
    f_clear clear;
    f_null isNull;
  #ifndef QT_NO_DATASTREAM
    f_load load;
    f_save save;
 #endif
    f_compare compare;
    f_convert convert;
    f_canConvert canConvert;
    f_debugStream debugStream;
};

Dieses Beispiel zeigt, wie QVariant Debug-Ausgabe zu hacken und zu String konvertieren. Dies ist sehr einfaches Beispiel, und Sie müssen es für Sie Problem zu verlängern. "Identifier" ist mein benutzerdefinierter Typ.

class HackVariant : private QVariant
{
public:
     static void hackIt() {
         origh = handler;
         Handler* h = new Handler;
         *h = *origh;
         h->convert = convert;
         h->debugStream = hackStreamDebug;
         handler = h;
     }

private:
     static bool convert(const QVariant::Private *d, QVariant::Type t, void *result, bool *ok)
     {
         //qDebug() << Q_FUNC_INFO << "type:" << d->type;
         if (d->type >= QVariant::UserType)
         {
             QString& str = *((QString*)result);
             Identifier* ident = (Identifier*)(constData(d));
             str = ident->toString();
         }
         else
             return origh->convert(d, t, result, ok);
         return true;
     }

     static void hackStreamDebug(QDebug dbg, const QVariant &v) {
         if (v.canConvert<Identifier>())
             dbg << v.value<Identifier>();
         else
             origh->debugStream(dbg, v);
     }

     static const Handler* origh;

     static const void *constData(const QVariant::Private *d)
     {
         return d->is_shared ? d->data.shared->ptr : reinterpret_cast<const void *>(&d->data.ptr);
     }

};

Sie haben Funktion zu erstellen und zu Handler gesetzt. Vergessen Sie nicht, Anruf HackVariant::hackIt() in main.cpp vor dem Gebrauch (var1 == var2).

Lösung für Qt 5

unterstützt Qt diese aus der Box seit Version 5.2. Siehe QVariant :: operator == und QMetaType :: registerComparators .

Lösung für Qt 4

Wenn Sie immer noch mit Qt 4 und nicht (oder nicht wollen) zu Qt 5 noch zu aktualisieren, können Sie die CustomVariantComparator Klasse, die ich für eine meiner Projekte geschrieben haben.

Sie können es verwenden, wie folgt. Lassen Sie uns sagen, dass wir eine Klasse Foo haben die Geräte operator== und sollte innerhalb eines QVariant verwendet werden:

class Foo {
public:
    bool operator==(const Foo &other) { return ...; }
};
Q_DECLARE_METATYPE(Foo)

Dann, einfach ausgedrückt die Q_DEFINE_COMPARATOR Makro neben der Implementierung von Foo (das heißt innerhalb der Foo.cpp Datei, aber nicht innerhalb der Foo.h-Datei):

Q_DEFINE_COMPARATOR(Foo)

Als nächstes nach den Aufbau Ihrer QApplication (oder QCoreApplication) So ermöglichen die benutzerdefinierte Variante Komparator (dies muss nur einmal getan werden):

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    CustomVariantComparator::setEnabled(true);
    // more code...
}

Nun wird der folgende Code-Schnipsel wird wie erwartet (das heißt invoke Foo::operator==).

QVariant::fromValue(Foo()) == QVariant::fromValue(Foo())
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top