QVariant::isNull() 和自定义类型

QVariant::isNull() and custom type

本文关键字:自定义 类型 isNull QVariant      更新时间:2023-10-16

我可以以某种方式将QVariant::isNull()与自定义Q_DECLARE_METATYPE()类型一起使用吗?

例如,如果我为整数定义这样一个包装类(我为什么要这样做,但这应该是一个最小的例子)。定义bool isNull() const成员函数无济于事:

#include <QVariant>
#include <QDebug>
class Integer {
    bool null;
    int x;
public:
    Integer() : null(true), x(0) {}
    Integer(int x) : null(false), x(x) {}
    int value() const {
        return x;
    }
    bool isNull() const {
        return null;
    }
};
Q_DECLARE_METATYPE(Integer)
int main()
{
    Integer x(42);
    Integer y(0);
    Integer z;
    qDebug() << x.isNull() << QVariant::fromValue(x).isNull();
    qDebug() << y.isNull() << QVariant::fromValue(y).isNull();
    qDebug() << z.isNull() << QVariant::fromValue(z).isNull(); // Not as expected!
}

输出:

false false 
false false 
true false     // Not as expected!
不幸的是你不能

QVariant::isNull代码如下:

static bool isNull(const QVariant::Private *d)
{
    switch(d->type) {
    case QVariant::String:
        return v_cast<QString>(d)->isNull();
    case QVariant::Char:
        return v_cast<QChar>(d)->isNull();
    case QVariant::Date:
        return v_cast<QDate>(d)->isNull();
    case QVariant::Time:
        return v_cast<QTime>(d)->isNull();
    ...
    }
    return d->is_null;
}

如您所见,它显式使用一些常见变量类型的isNull()函数,默认情况下它返回d->is_null值。

d->is_nullQVariant类的 D 指针的类成员,该指针初始化为 true但每次为QVariant赋值时,它都会变为false

inline void qVariantSetValue(QVariant &v, const T &t)
{
    ...
    d.is_null = false;
    ...
}

因此,对于自定义类型,它将始终返回 false

一种可能性(我不推荐)是子类QVariant并重新实现isNull函数。在此函数中,您可以检查类型是否为自定义类型,在这种情况下,您可以返回自定义类的 isNull 函数的返回值,否则应返回 QVariant::isNull 函数的返回值。

bool MyQVariant::isNull() const
{
    if (QString(typeName()) == "MyCustomClass")
       return value<MyCustomClass>().isNull();
    return QVariant::isNull();   
}

编辑

使用子类化 QVariant 的示例代码:

#include <QVariant>
#include <QDebug>
class Integer {
    bool null;
    int x;
public:
    Integer() : null(true), x(0) {}
    Integer(int x) : null(false), x(x) {}
    int value() const {
        return x;
    }
    bool isNull() const {
        return null;
    }
};
Q_DECLARE_METATYPE(Integer)
class MyQVariant : public QVariant
{
public:
    MyQVariant(QVariant v) :
      QVariant(v) {}
    bool isNull() const
    {
        if (QString(typeName()) == "Integer")
            return value<Integer>().isNull();
        return QVariant::isNull();   
    }
};
int main(int argc, char *argv[])
{
    Integer x(42);
    Integer y(0);
    Integer z;
    qRegisterMetaType<Integer>("Integer");
    MyQVariant v1(QVariant::fromValue(x));
    MyQVariant v2(QVariant::fromValue(y));
    MyQVariant v3(QVariant::fromValue(z));
    qDebug() << x.isNull() << v1.isNull();
    qDebug() << y.isNull() << v2.isNull();
    qDebug() << z.isNull() << v3.isNull();
}

输出:

false false 
false false 
true true