saving a custom Unit* class



  • I have a class which is a QObject and it has a member which is a Unit *.

    The saving is complaining that it can not save a Unit *

    [26.04 12:53:21 W] QVariant::save: unable to save type 'Unit*' (type id: 1362).
    
    ```I tried to register it with  ```
    qRegisterMetaTypeStreamOperators
    
    
    
    /usr/include/qt/QtCore/qvariant.h:465: error: 'QVariant::QVariant(void*)' is private
         inline QVariant(void *) Q_DECL_EQ_DELETE;
    
    ```            ^
    Here is my loading and saving mechanism
    

    void Profile::save(QSettings& settings) const {
    for(int i=0; i<metaObject()->propertyCount(); ++i) {
    const auto& p = metaObject()->property(i);
    if(p.isStored(this)) {
    settings.setValue(p.name(), property(p.name()));
    }
    }
    }

    void Profile::load(QSettings& settings) {
    for(int i=0; i<metaObject()->propertyCount(); ++i) {
    const auto& p = metaObject()->property(i);
    if(p.isStored(this)) {
    setProperty(p.name(), settings.value(p.name()));
    }
    }
    }

    here is my unit class
    

    Unit::Unit(int unit, QObject *parent)
    : EraObject(parent),
    m_value(0.0),
    m_unit(unit)
    {
    connect(eApp->systemController()->unitManager(),&UnitManager::onUnitChanged,this,&Unit::changeUnit);
    }

    Unit::Unit(const Unit &other)
    {
    m_value = other.m_value;
    m_unit = other.m_unit;
    qRegisterMetaTypeStreamOperators<Unit*>("Unit*");
    }

    Unit &Unit::operator=(const qreal value)
    {
    if (m_value == value)
    return *this;

    m_value = value;
    emit userValueChanged();
    
    return *this;
    

    }

    void Unit::loadFrom(Settings &set, bool ownGroup)
    {
    Q_UNUSED(ownGroup)
    if(set.contains(objectName())) {
    m_value = set.value(objectName(),0.0).toDouble();
    emit userValueChanged();
    }
    }

    void Unit::saveTo(Settings &set, bool ownGroup, bool force)
    {
    Q_UNUSED(ownGroup)
    Q_UNUSED(force)
    set.setValue(objectName(),m_value);
    }

    Unit::operator qreal() const
    {
    return m_value;
    }

    qreal Unit::userValue() const
    {
    return isDefault() ? m_value : UnitManager::convertTo(m_value,m_unit);
    }

    QString Unit::symbol() const
    {
    return UnitManager::symbolName(m_unit);
    }

    void Unit::setUserValue(const qreal userValue)
    {
    qDebug() << "setUserValue" << this->userValue() << userValue << QString::number(m_unit,2);
    if (this->userValue() == userValue)
    return;

    if(isDefault())
        m_value = userValue;
    else
        m_value = UnitManager::convertFrom(userValue,m_unit);
    
    qDebug() << "Value" <<  m_value;
    
    emit userValueChanged();
    setDirty(RamDirty);
    

    }

    void Unit::setup(quint32 unit, const QString name, QObject *parent)
    {
    if(!m_unit)
    m_unit = (unit << 16);
    setObjectName(name);
    setParent(parent);
    connectDirtyWithParent(parent);
    }

    void Unit::changeUnit(const quint32 &unit)
    {
    if(m_unit == unit || category() != (unit >> 16))
    return;
    m_unit = unit;
    emit userValueChanged();
    emit symbolChanged();
    }


  • Lifetime Qt Champion

    Hi,

    Did you also implement the stream operators ?

    Note that there's something wrong going on here. You have implement a copy operator for your QObject based class which wrong. QObject is note a copyable class, see here for more information.



  • I implemented the stream operators >> and << and still I can't save the qobject pointer into the file settings. I don't know why. what else do you need to dig for the problem ?

    and thanks for the note


  • Lifetime Qt Champion

    Can you share your operators implementation ?



  • why I can't save a pointer qproperty like Unit*.
    that's what the error says
    QVariant::save: unable to save type 'Unit*'


  • Lifetime Qt Champion

    I don't know since you didn't share the complete code. Anyway, here is a dummy implementation that shows how it works:

    class MyObject : public QObject
    {
    public:
        MyObject(QObject *parent = 0)
            : QObject(parent)
        {}
    
        QString foo() const { return _foo; }
        void setFoo(const QString& foo) {
            _foo = foo;
        }
    
    private:
        QString _foo;
    };
    
    QDataStream &operator<<(QDataStream &ds, MyObject *object)
    {
        ds << object->foo();
        return ds;
    }
    
    QDataStream &operator>>(QDataStream &ds, MyObject *object)
    {
        QString foo;
        ds >> foo;
        object->setFoo(foo);
        return ds;
    }
    
    QDebug operator<<(QDebug dbg, MyObject *object)
    {
        dbg << object->metaObject()->className() << object->foo();
        return dbg;
    }
    
    Q_DECLARE_METATYPE(MyObject *)
    
    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
        qRegisterMetaType<MyObject *>();
        qRegisterMetaTypeStreamOperators<MyObject *>();
        MyObject *object = new MyObject;
        object->setFoo("myfoo");
    
        QBuffer buffer;
        buffer.open(QBuffer::WriteOnly);
        QDataStream ds(&buffer);
        ds << object;
        buffer.close();
    
        // later
        buffer.open(QBuffer::ReadOnly);
        ds.setDevice(&buffer);
        MyObject *object2 = new MyObject;
        ds >> object2;
    
        qDebug() << object2;
        delete object;
        delete object2;
        return 0;
    }
    


  • I'm trying to define the operators >> and << for a custom class called Unit, and I need to store a pointer.

    here is how I define the functions

    QDataStream &operator<<(QDataStream &out, const Unit *unit)
    {
    out << unit->value();
    return out;
    }

    QDataStream &operator>>(QDataStream &in, Unit *unit)
    {
    double value;
    in >> value;
    unit->setUserValue(value);
    return in;
    }

    void Unit::setUserValue(const qreal userValue)
    {
    qDebug() << "setUserValue" << this->userValue() << userValue << QString::number(m_unit,2);
    if (this->userValue() == userValue)
    return;

    if(isDefault())
        m_value = userValue;
    else
        m_value = UnitManager::convertFrom(userValue,m_unit);
    
    qDebug() << "Value" <<  m_value;
    
    emit userValueChanged();
    setDirty(RamDirty);
    

    }

    qRegisterMetaType<Unit*>();
    qRegisterMetaTypeStreamOperators<Unit *>();
    I'm getting the following compilation error message

    error: no match for 'operator>>' (operand types are 'QDataStream' and 'Unit*')
    and also an error here

    /usr/include/qt/QtCore/qmetatype.h:771: error: invalid initialization of non-const reference of type 'quint8& {aka unsigned char&}' from an rvalue of type 'quint8 {aka unsigned char}'
    stream >> static_cast<T>(t);
    ^
    I also defined the meta type

    Q_DECLARE_METATYPE(Unit)
    Q_DECLARE_METATYPE(Unit*)


  • Lifetime Qt Champion

    Unit is a QObject base class you shouldn't call Q_DECLARE_METATYPE on it.

    Where are you doing the declaration and registrations ?



  • I'm doing it in main()


  • Lifetime Qt Champion

    Something's wrong with your streaming operations, you don't save and load the same formats you use for your class. You have qreal on one side then double on another side.

    You should really be precise when doing such operations.



  • I'm still getting the following error

    /usr/include/qt/QtCore/qmetatype.h:771: error: no match for 'operator>>' (operand types are 'QDataStream' and 'Unit')
             stream >> *static_cast<T*>(t);
                    ^
    
    
    QDataStream &operator<<(QDataStream &out, const Unit *&unit)
    {
       out << unit->value();
       return out;
    }
    
    QDataStream &operator>>(QDataStream &in, Unit *&unit)
    {
       qreal value;
       in >> value;
       unit->setUserValue(value);
       return in;
    }
    

    In MAIN I define

    qRegisterMetaType<Unit*>();
    qRegisterMetaTypeStreamOperators<Unit *>();
    
    ```in the header of Unit.h I define
    

    Q_DECLARE_METATYPE(Unit*)
    Q_DECLARE_METATYPE(Unit)


  • Qt Champions 2016

    @AndreAhmed said:

    /usr/include/qt/QtCore/qmetatype.h:771: error: no match for 'operator>>' (operand types are 'QDataStream' and 'Unit')
    stream >> static_cast<T>(t);

    Follow the compiler's error description! You're trying to save an instance of the class (i.e. an object), then you provide operators for saving a pointer to that class ... the compiler can't match one to the other.

    QDataStream &operator>>(QDataStream &out, Unit *&unit)
    

    is quite different from:

    QDataStream &operator>>(QDataStream &out, Unit &unit)  //< This is what you're invoking with stream >> *static_cast<Unit*>(t);
    

    Additionally, don't pass pointer references, unless you intend on changing them ... this could have unforeseen consequences if in the implementation you do something along the lines of:

    unit = nullptr;
    

    for example.

    Best is to even make a further step (although it's often considered quite over-protective) and make sure the pointer will not be moved, not only that it's pointing to a const object:

    QDataStream &operator<<(QDataStream &out, const Unit * const unit) //< Forbid moving the pointer inside the implementation, not only modifying the object
    {
    }
    
    QDataStream & operator >> (QDataStream & in, Unit * const unit) //< Again, the pointer is constant, can't be modified, the object is not though
    {
    }
    

Log in to reply
 

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