[英]How to support comparisons for QVariant objects containing a custom type?
根据Qt文档,如果变体包含自定义类型, QVariant::operator==
无法正常工作:
bool QVariant :: operator ==(const QVariant&v)const
将此QVariant与v进行比较,如果它们相等则返回true; 否则返回false。
在自定义类型的情况下,不调用它们的相等运算符。 而是比较值的地址。
你怎么能让这个为你的自定义类型表现得有意义? 在我的例子中,我将枚举值存储在QVariant中,例如
在标题中:
enum MyEnum { Foo, Bar };
Q_DECLARE_METATYPE(MyEnum);
功能中的某个地方:
QVariant var1 = QVariant::fromValue<MyEnum>(Foo);
QVariant var2 = QVariant::fromValue<MyEnum>(Foo);
assert(var1 == var2); // Fails!
为了使这个断言成为现实,我需要做些什么呢?
我理解为什么它不起作用 - 每个变体都存储枚举值的单独副本,因此它们具有不同的地址。 我想知道如何改变我在变体中存储这些值的方法,以便这不是一个问题,或者它们都引用相同的底层变量。
它不认为我可以绕过需要平等比较才能工作。 上下文是我使用此枚举作为QComboBox
中的项目中的UserData,并且我希望能够使用QComboBox::findData
来定位与特定枚举值对应的项目索引。
显而易见的答案是使用var1.value<MyEnum>() == var2.value<MyEnum>()
来转换数据以进行比较,但这需要您在比较时知道类型。 在您的情况下,这似乎是可能的。
如果您只是使用枚举,您还可以将其转换为int以存储在QVariant中。
编辑:有关搜索QComboBox
,它使用组合框的模型来查找数据 。 具体来说,它使用QAbstractItemModel
的match()
函数来检查是否相等。 幸运的是,这个函数是虚函数,所以你可以在子类中覆盖它。
尝试hack qvariant,按原型定义函数
typedef bool (*f_compare)(const Private *, const Private *);
并将其设置为qvariant处理程序; 要使用qvariant qt,请使用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;
};
此示例演示如何破解qvariant调试输出并转换为字符串。 这是一个非常简单的示例,您需要为您解决问题。 “标识符”是我的自定义类型。
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);
}
};
您必须创建函数并将其设置为处理程序。 在使用之前不要忘记在main.cpp中调用HackVariant::hackIt()
(var1 == var2)。
自5.2版本开始,Qt就开箱即用。 请参阅QVariant :: operator ==和QMetaType :: registerComparators 。
如果你还在使用Qt 4而且不能(或者不想)升级到Qt 5,你可以使用我为我的一个项目编写的CustomVariantComparator类。
您可以按如下方式使用它。 假设我们有一个实现operator==
的类Foo
,应该在QVariant
:
class Foo {
public:
bool operator==(const Foo &other) { return ...; }
};
Q_DECLARE_METATYPE(Foo)
然后,只需将Q_DEFINE_COMPARATOR
宏放在Foo
的实现旁边(即在Foo.cpp
文件中,但不在Foo.h
文件中):
Q_DEFINE_COMPARATOR(Foo)
接下来, 在构建QApplication
(或QCoreApplication
)实例之后,启用自定义变量比较器(这只需要执行一次):
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
CustomVariantComparator::setEnabled(true);
// more code...
}
现在,以下代码片段将按预期工作(即调用Foo::operator==
)。
QVariant::fromValue(Foo()) == QVariant::fromValue(Foo())
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.