QDebug with custom typed QVariant



  • Hi all,

    I am having a custom type which I use with QVariant. Everything works fine here.
    One thing I seem not be able to do though is to properly serialize it to debug output.
    For instance:

      QColor colr;
      QVariant colorv = QVariant::fromValue(colr);
    
      qDebug() << colorv;
    

    generates such output:

    QVariant(QColor, QColor(Invalid))

    My type generates such:

    QVariant(Point3F, )

    My type is registered with Q_DECLARE_METATYPE and has its own << operator defined which is never called:

    Q_DECLARE_METATYPE(Point3F);
    QDebug operator << (QDebug, const Point3F&);
    

    Anyone knows how I can ensure stream operator is called if I stream the variant containing my type ?

    Cheers!


  • Moderators

    @enmaniac

    You need a custom streaming operator for QDebug. Here is an example in the docs for QDebug.

    [edit:koahnig] Sorry, I did not see the part related to QVariant. I guess that would as if converted back to your original object.
    probably like

    qDebug() << colorv.value<QColor>();
    


  • Hi @koahnig ,

    You mean that ?

    QDebug operator << (QDebug, const Point3F&);
    

    I already have it but it does not seem to be called.


  • Moderators

    @enmaniac
    Sorry, I had not read completely to the end.

    I did not see the part related to QVariant. I guess that would as if converted back to your original object.
    probably like

    qDebug() << colorv.value<QColor>();



  • Yes, that probably would work but thats what I would like to avoid doing, since I log many different types with the single log function.

    Somehow, for Qt types like QSize and QColor streaming the QVariant into QDebug works just fine. Their streaming operators are called.
    I would like to find out what needs to be done for custom types in order for QVariant to actually call the custom stream handler.

    Probably, there is a way to install my handler for particular custom type but I am not sure.

    Looking into the code I could see the following for QVariant:

    QDebug operator<<(QDebug dbg, const QVariant &v)
    {
        QDebugStateSaver saver(dbg);
        const uint typeId = v.d.type;
        dbg.nospace() << "QVariant(";
        if (typeId != QMetaType::UnknownType) {
            dbg << QMetaType::typeName(typeId) << ", ";
            bool userStream = false;
            bool canConvertToString = false;
            if (typeId >= QMetaType::User) {
                userStream = QMetaType::debugStream(dbg, constData(v.d), typeId);
                canConvertToString = v.canConvert<QString>();
            }
            if (!userStream && canConvertToString)
                dbg << v.toString();
            else if (!userStream)
                handlerManager[typeId]->debugStream(dbg, v);
        } else {
            dbg << "Invalid";
        }
        dbg << ')';
        return dbg;
    }
    

    If I could somehow make my type convertable to QString maybe it would work, though I dont know how to accomplish it.


  • Lifetime Qt Champion

    Hi,

    What does your custom debug << operator do ?



  • Hi!

    Nothing special just logs some data:

    QDebug operator << (QDebug debug, const Point3F& point)
    {
      QDebugStateSaver saver(debug);
    
      debug.nospace() << "Point3F(" << point.x() << ", " << point.y() << ", " << point.z() << ")";
    
      return debug;
    }
    

    Note that if I do stream the object directly it works as expected e.g.:

    qDebug() << Point3F();
    

    Shows:

    Point3F(0, 0, 0)

    It is just when the object is inside of QVariant, the logging is broken.



  • I am not sure if it is possible or how to add the file here with a sample project but there is the full example for anyone interested to test:

    #include <QCoreApplication>
    #include <QString>
    #include <QVariant>
    #include <QDebug>
    #include <QSize>
    
    class MyClass
    {
      public:
    
        MyClass() {}
        MyClass(const QString& text) : m_text(text) {}
        MyClass(const MyClass& other) : m_text(other.text()) {}
    
        const QString& text() const { return m_text; }
    
      private:
    
        QString m_text;
    };
    Q_DECLARE_METATYPE(MyClass);
    QDebug operator << (QDebug debug, const MyClass& object)
    {
      debug.nospace() << "MyClass(" << object.text() << ")";
    
      return debug;
    }
    int main(int argc, char *argv[])
    {
      QCoreApplication app(argc, argv);
    
      MyClass myClass("This is my text");
      QVariant vMyClass = QVariant::fromValue(myClass);
    
      // Qt type for which everything works just fine
      qDebug() << QSize();
      qDebug() << QVariant::fromValue(QSize());
    
      qDebug() << myClass;  // This produces: MyClass("This is my text")
      qDebug() << vMyClass; // This procudes: QVariant(MyClass, )
                            // while it should: QVariant(MyClass, MyClass("This is my text") )
    
      return app.exec();
    }
    
    I have tested on Ubuntu, Qt 4.8.1 and Qt 5.6.0

  • Qt Champions 2016

    I believe you need to register the debug stream operator.



  • @kshegunov Thank you! That was the missing part!!



Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.