Ran*_*zen 11 c++ qt qvariant qt5
我创建了一个qt bugticket希望文档将被扩展.
相信2010年的问题和Qt文档,operator==()不适用于自定义类型.
引用:
bool QVariant :: operator ==(const QVariant&v)const
将此QVariant与其进行比较
v,true如果它们相等则返回; 否则返回false.
QVariant使用它包含的type()的相等运算符来检查是否相等.如果它的类型与此变体的类型不同,QVariant将尝试convert()v.查看canConvert()可能的转换列表.警告:此功能不支持注册的自定义类型
qRegisterMetaType().
我试图从2010年的Stackoverflow问题重现repro案例,并且比较对我没有任何问题.
我也更进一步,尝试使用自己的类进行比较,这也很完美.要重现,请将以下代码放入任何标头中:
enum MyEnum { Foo, Bar };
Q_DECLARE_METATYPE(MyEnum)
class MyClass
{
int value;
public:
MyClass() : value(0)
{
}
MyClass(int a) : value(a)
{
}
bool operator==(const MyClass &) const
{
Q_ASSERT(false); // This method seems not to be called
return false;
}
bool operator!=(const MyClass &) const
{
Q_ASSERT(false); // This method seems not to be called
return true;
}
};
Q_DECLARE_METATYPE(MyClass)
Run Code Online (Sandbox Code Playgroud)
并将以下代码转换为任何函数:
QVariant var1 = QVariant::fromValue<MyEnum>(Foo);
QVariant var2 = QVariant::fromValue<MyEnum>(Foo);
Q_ASSERT(var1 == var2); // Succeeds!
var1 = QVariant::fromValue<MyEnum>(Foo);
var2 = QVariant::fromValue<MyEnum>(Bar);
Q_ASSERT(var1 != var2); // Succeeds!
QVariant obj1 = QVariant::fromValue<MyClass>(MyClass(42));
QVariant obj2 = QVariant::fromValue<MyClass>(MyClass(42));
Q_ASSERT(obj1 == obj2); // Succeeds!
obj1 = QVariant::fromValue<MyClass>(MyClass(42));
obj2 = QVariant::fromValue<MyClass>(MyClass(23));
Q_ASSERT(obj1 != obj2); // Succeeds!
Run Code Online (Sandbox Code Playgroud)
我猜想在较新的qt版本中,使用时会获取类型的大小,Q_DECLARE_METATYPE因此QVariant可以按字节顺序比较未知类型的值.
但这只是一个猜测,我不想通过猜测qt做什么而不是依赖文档来冒险应用程序的稳定性.
我可以找出QVariant如何比较未知类型吗?我更愿意依赖规范而不是实现.
pep*_*ppe 21
我担心你需要依赖代码(而且,作为行为,它不能在没有破坏的情况下改变),而不是文档.不过,下面有一个惊喜.
QVariant::operator==对于具有未注册运算符的类型,只需使用memcmp.相关片段(在5.1中)是这样的:
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);
}
Run Code Online (Sandbox Code Playgroud)
handlerManager是一个全局对象,用于执行类型感知操作.它包含一组QVariant::Handler对象; 每个这样的对象都包含指针,用于对他们知道如何处理的类型执行某些操作:
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;
};
Run Code Online (Sandbox Code Playgroud)
这些成员中的每一个实际上都是指向函数的指针.
拥有这个全局对象数组的原因有点复杂 - 它允许其他Qt库(比如QtGui)为这些库中定义的类型安装自定义处理程序(fi QColor).
该operator[]对handlerManager将执行一些额外的魔法,也就是让每个模块的处理程序是给定类型的权利:
return Handlers[QModulesPrivate::moduleForType(typeId)];
Run Code Online (Sandbox Code Playgroud)
现在类型当然是一个自定义类型,因此这里返回的Handler是Unknown模块中的一个.这Handler将使用customCompare函数in qvariant.cpp,它执行此操作:
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));
}
Run Code Online (Sandbox Code Playgroud)
除了一些错误检查和以特殊方式处理共享和null变体之外,还使用memcmp了内容.
...只有当类型不是指针类型时,似乎.不知道为什么那里的代码......
从Qt 5.2开始,您可以使用QMetaType::registerComparator(请参阅此处)进行Qt调用operator<以及operator==您的自定义类型.只需添加到您的main:
qRegisterMetaType<MyClass>();
QMetaType::registerComparators<MyClass>();
Run Code Online (Sandbox Code Playgroud)
瞧,你会在你的平等运算符中找到断言.QVariant::cmp现在是:
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);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4194 次 |
| 最近记录: |