首页 文章

如何支持包含自定义类型的QVariant对象的比较?

提问于
浏览
22

根据Qt文档,如果变体包含自定义类型, QVariant::operator== 无法正常工作:

bool QVariant :: operator ==(const QVariant&v)const将此QVariant与v进行比较,如果它们相等则返回true;否则返回false . 在自定义类型的情况下,不调用它们的相等运算符 . 而是比较值的地址 .

你怎么能让这个为你的自定义类型表现得有意义?在我的例子中,我将枚举值存储在QVariant中,例如

在 Headers 中:

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 来查找与特定枚举值对应的项目索引 .

3 回答

  • 4

    显而易见的答案是使用 var1.value<MyEnum>() == var2.value<MyEnum>() 来转换数据以进行比较,但这需要您在比较时知道类型 . 看起来在你的情况下这可能是可能的 .

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

    编辑:有关搜索QComboBox的说明,请uses the model of the combo box to find the data . 具体来说,它使用QAbstractItemModelmatch()函数来检查是否相等 . 幸运的是,这个函数是虚函数,所以你可以在子类中覆盖它 .

  • 15

    尝试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) .

  • 4

    Qt 5的解决方案

    自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)
    

    接下来, after 构造您的 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())
    

相关问题