Cómo ayudar a las comparaciones de objetos QVariant que contienen un tipo personalizado?

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

  •  01-10-2019
  •  | 
  •  

Pregunta

De acuerdo con la documentación de Qt, QVariant::operator== no funciona como cabría esperar si la variante contiene un tipo personalizado:

  

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

     

compara esta QVariant con v y   devuelve verdadero si son iguales;   de lo contrario retorna falso.

     

En el caso de los tipos personalizados, su   operadores equalness no son llamados.   En lugar direcciones son los valores   comparación.

¿Cómo se supone para conseguir que esto comporte de manera significativa para sus tipos personalizados? En mi caso, estoy almacenando un valor enumerado en un QVariant, por ejemplo.

En un encabezado:

enum MyEnum { Foo, Bar };

Q_DECLARE_METATYPE(MyEnum);

En algún lugar de una función:

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

¿Qué tengo que hacer de manera diferente con el fin de esta afirmación para ser verdad?

entiendo ¿Por qué que no está funcionando - cada variante está almacenando una copia separada del valor enumerado, por lo que tienen diferentes direcciones. Quiero saber cómo puedo cambiar mi enfoque para almacenar estos valores en las variantes por lo que, o bien esto no es un problema, o para que hagan referencia tanto a la misma variable subyacente.

No creo que sea posible para mí para moverse necesidad de comparaciones de igualdad al trabajo. El contexto es que estoy usando esta enumeración como el UserData en elementos de una QComboBox y quiero ser capaz de utilizar QComboBox::findData para localizar el índice de elemento correspondiente a un valor enumerado en particular.

¿Fue útil?

Solución

La respuesta obvia es a emitir los datos fuera de la var1.value<MyEnum>() == var2.value<MyEnum>() compararlos, pero que requiere que conocer el tipo cuando se comparan. Parece que, en su caso esto podría ser posible.

Si usted está usando las enumeraciones, que también podría convertirlo en un int para el almacenamiento en el QVariant.

Editar: Para mayor claridad acerca de búsquedas en una QComboBox , es utiliza el modelo del cuadro combinado para encontrar los datos . Específicamente, se utiliza el match() función de la QAbstractItemModel para comprobar la igualdad. Por suerte, esta función es virtual para que pueda anularlo en una subclase.

Otros consejos

Trate QVariant corte, definir la función de prototipo

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

y configurarlo para manejador QVariant; Para trabajar con QVariant qt uso 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;
};

Este ejemplo demuestra cómo cortar la salida de depuración QVariant y convertir a cadena. Esto es muy simple ejemplo, y hay que extenderlo para usted un problema. "Identificador" es mi tipo personalizado.

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

};

Hay que crear la función y la puso al controlador. No se olvide HackVariant::hackIt() llamada en main.cpp antes de su uso (var1 var2 ==).

Solución para Qt 5

Qt apoya esta fuera de la caja desde la versión 5.2. Ver QVariant :: operador == y href="http://doc.qt.io/qt-5/qmetatype.html#registerComparators" rel="nofollow"> QMetaType :: registerComparators .

Solución para Qt 4

Si usted todavía está utilizando Qt 4 y no puede (o no quieren) para actualizar a Qt 5, sin embargo, se puede utilizar el CustomVariantComparator clase que he escrito en uno de mis proyectos.

Se puede utilizar de la siguiente manera. Digamos que tenemos una clase que implementa Foo operator== y deben utilizarse dentro de un QVariant:

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

A continuación, sólo tiene que poner la macro Q_DEFINE_COMPARATOR junto a la implementación de Foo (es decir, dentro del archivo Foo.cpp, pero no dentro del archivo Foo.h):

Q_DEFINE_COMPARATOR(Foo)

A continuación, después construcción de la instancia QApplication (o QCoreApplication), permiten al comparador variante personalizada (esto sólo tiene que hacer una vez):

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

Ahora, el siguiente fragmento de código funcionará como se espera (es decir invoke Foo::operator==).

QVariant::fromValue(Foo()) == QVariant::fromValue(Foo())
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top