22

根据 Qt 文档,QVariant::operator==如果变体包含自定义类型,则不会像预期的那样工作:

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

将此 QVariant 与 v 进行比较,如果相等则返回 true;否则返回假。

在自定义类型的情况下,不调用它们的相等运算符。而是比较值的地址。

你应该如何让它对你的自定义类型有意义?就我而言,我将枚举值存储在 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!

为了使这个断言成立,我需要做些什么不同的事情?

我理解为什么它不起作用——每个变体都存储枚举值的单独副本,因此它们具有不同的地址。我想知道如何更改将这些值存储在变体中的方法,以便这不是问题,或者它们都引用相同的基础变量。

它认为我不可能绕过需要平等比较才能工作。上下文是我将此枚举用作 a 中项目中的 UserData,QComboBox并且我希望能够使用它QComboBox::findData来定位与特定枚举值相对应的项目索引。

4

3 回答 3

15

显而易见的答案是将数据从 with中剔除var1.value<MyEnum>() == var2.value<MyEnum>()以比较它们,但这需要您在比较时知道类型。在您的情况下,这似乎是可能的。

如果您只是使用枚举,您还可以将其转换为 int 以存储在 QVariant 中。

编辑:为了澄清搜索 a QComboBox,它使用组合框的模型来查找 data。具体来说,它使用 的match()函数QAbstractItemModel来检查是否相等。幸运的是,这个函数是虚拟的,所以你可以在子类中重写它。

于 2010-05-19T20:05:29.577 回答
4

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

};

您必须创建函数并将其设置为处理程序。不要忘记HackVariant::hackIt()在使用前调用 main.cpp (var1 == var2)。

于 2012-08-15T16:59:27.220 回答
4

Qt 5 的解决方案

Qt 自 5.2 版起即支持此功能。请参阅QVariant::operator==QMetaType::registerComparators

Qt 4 的解决方案

如果您仍在使用 Qt 4 并且还不能(或不想)升级到 Qt 5,您可以使用我为我的一个项目编写的CustomVariantComparator类。

您可以按如下方式使用它。假设我们有一个Foo实现operator==并且应该在 a 中使用的类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(or QCoreApplication) 实例后,启用自定义变体比较器(只需执行一次):

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

现在,以下代码片段将按预期工作(即调用Foo::operator==)。

QVariant::fromValue(Foo()) == QVariant::fromValue(Foo())
于 2015-03-17T22:49:03.337 回答