I have created an qt bugticket hoping the documentation will be extended.
Believing an Question from 2010 and the Qt Documen
I'm afraid you'll need to rely on the code (and, being behaviour, it can't be changed without breaking), and not documentation. There's a surprise just below, though.
QVariant::operator==
for types with unregistered operators will just use memcmp
. The relevant snippet (in 5.1) is this:
bool QVariant::cmp(const QVariant &v) const
{
QVariant v1 = *this;
QVariant v2 = v;
if (d.type != v2.d.type)
// handle conversions....
return handlerManager[v1.d.type]->compare(&v1.d, &v2.d);
}
handlerManager
is a global object that gets used to perform type-aware manipulations. It contains an array of QVariant::Handler
objects; each of such objects contains pointers to perform certain operations on the types they know how to handle:
struct Handler {
f_construct construct;
f_clear clear;
f_null isNull;
f_load load;
f_save save;
f_compare compare;
f_convert convert;
f_canConvert canConvert;
f_debugStream debugStream;
};
Each and every of those members is actually a pointer to a function.
The reason for having this array of global objects is a bit complicated -- it's for allowing other Qt libraries (say, QtGui) to install custom handlers for the types defined in those libs (f.i. QColor).
The operator[]
on the handlerManager
will perform some extra magic, namely get the right per-module handler given the type:
return Handlers[QModulesPrivate::moduleForType(typeId)];
Now the type is of course a custom type, so the Handler returned here is the one the Unknown
module. That Handler
will use the customCompare
function in qvariant.cpp
, which does this:
static bool customCompare(const QVariant::Private *a, const QVariant::Private *b)
{
const char *const typeName = QMetaType::typeName(a->type);
if (Q_UNLIKELY(!typeName) && Q_LIKELY(!QMetaType::isRegistered(a->type)))
qFatal("QVariant::compare: type %d unknown to QVariant.", a->type);
const void *a_ptr = a->is_shared ? a->data.shared->ptr : &(a->data.ptr);
const void *b_ptr = b->is_shared ? b->data.shared->ptr : &(b->data.ptr);
uint typeNameLen = qstrlen(typeName);
if (typeNameLen > 0 && typeName[typeNameLen - 1] == '*')
return *static_cast<void *const *>(a_ptr) == *static_cast<void *const *>(b_ptr);
if (a->is_null && b->is_null)
return true;
return !memcmp(a_ptr, b_ptr, QMetaType::sizeOf(a->type));
}
Which, apart from a bit of error checking and handling shared and null variants in a special way, uses memcmp
on the contents.
... only if the type is not a pointer type, it seems. Wonder why there's that code there...
Starting with Qt 5.2, you can use QMetaType::registerComparator
(see here) to make Qt invoke operator<
and operator==
on your custom type. Just add to your main
:
qRegisterMetaType<MyClass>();
QMetaType::registerComparators<MyClass>();
And voilà, you'll hit the assert in your equality operator. QVariant::cmp
now is:
QVariant v1 = *this;
QVariant v2 = v;
if (d.type != v2.d.type)
// handle conversions, like before
// *NEW IMPORTANT CODE*
if (v1.d.type >= QMetaType::User) {
// non-builtin types (MyClass, MyEnum...)
int result;
// will invoke the comparator for v1's type, if ever registered
if (QMetaType::compare(QT_PREPEND_NAMESPACE(constData(v1.d)), QT_PREPEND_NAMESPACE(constData(v2.d)), v1.d.type, &result))
return result == 0;
}
// as before
return handlerManager[v1.d.type]->compare(&v1.d, &v2.d);