Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QVariant::isNull() and custom type

Tags:

c++

qt

Can I somehow use QVariant::isNull() with a custom Q_DECLARE_METATYPE() type?

For example, if I define such a wrapper class for an integer (why should I, but this should be a minimal example). Defining a bool isNull() const member function doesn't help:

#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!
}

Output:

false false 
false false 
true false     // Not as expected!
like image 995
groaner Avatar asked Jan 23 '13 17:01

groaner


1 Answers

Unfortunately you can't. The QVariant::isNull code is the following:

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;
}

As you can see it explicitely uses the isNull() function of some common variable types and by default it returns the d->is_null value.

The d->is_null is a class member of the D pointer of the QVariant class which is initialized to true but every time you assign a value to the QVariant it becomes false:

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

So for custom types it will always return false.

One possibility (which I do not recommend) would be to subclass QVariant and reimplement the isNull function. In this function you could check if the type is custom and in this case you can return the return value of the isNull function of your custom class, otherwise you should return the return value of the QVariant::isNull function.

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

EDIT

Your example code using the subclassed 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();
}

Output:

false false 
false false 
true true
like image 55
pnezis Avatar answered Oct 16 '22 13:10

pnezis