c++qttemplatesqsettingsqvariant

Qt/C++ Serialize generic object into QSettings


I have several occurences in my application where I want to save a compound object into QSettings:

template <typename T>
class AwsProperty
{
public:
    AwsProperty(T value, quint64 timestamp){
        m_data = value;
        m_timestamp = timestamp;
    }
    AwsProperty(){}
    T value(){return m_data;}
    void update(T value,quint64 timestamp){m_data = value; m_timestamp = timestamp;}
    quint64 timestamp(){return m_timestamp;}

    void toQDataStream(QDataStream &dstream){dstream << m_data << m_timestamp;}
    void fromQDataStream(QDataStream &dstream){dstream >> m_data >> m_timestamp;}
private:
    quint64 m_timestamp;
    T m_data;
};

typedef AwsProperty<qint32> AwsPropertyInt32;
Q_DECLARE_METATYPE(AwsPropertyInt32)
typedef AwsProperty<quint32> AwsPropertyUint32;
Q_DECLARE_METATYPE(AwsPropertyUint32)
typedef AwsProperty<bool> AwsPropertyBool;
Q_DECLARE_METATYPE(AwsPropertyBool)

the cpp looks like this:

template <typename T>
QDataStream& operator<<(QDataStream& out, const AwsProperty<T>& classObj){
{
    classObj.toQDataStream(out);
    return out;
}
template <typename T>
QDataStream& operator>>(QDataStream& in, const AwsProperty<T>& classObj){
    classObj.fromQDataStream(in);
    return in;
}

I registered them in my main:

  qRegisterMetaTypeStreamOperators<AwsPropertyInt32>("AwsPropertyInt32");
    qRegisterMetaTypeStreamOperators<AwsPropertyUint32>("AwsPropertyUint32");
    qRegisterMetaTypeStreamOperators<AwsPropertyBool>("AwsPropertyBool");

The error I am getting is:

/opt/XXXXXXXXXX/0.9.99/sysroots/cortexa9hf-neon-XXXXXX-linux-gnueabi/usr/include/QtCore/qmetatype.h:810: error: no match for ‘operator<<’ (operand types are ‘QDataStream’ and ‘const AwsProperty<int>’)
         stream << *static_cast<const T*>(t);
         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~

Also why is the streaming operator not defined for QDataStream and QString.


Solution

  • You have to register the operators to the metatype system using qRegisterMetaTypeStreamOperators before instantiating QSettings.

    Also, the constness of the operators and the fromQDataStream and toQDataStream methods is slightly wrong (see the link for the exact prototype that is needed).

    EDIT:

    This code works for me: Note that I changed the constness of some methods and move the operators to the header file since they are templates.

    awsproperty.h

    #include <QDataStream>
    
    template <typename T>
    class AwsProperty
    {
    public:
        AwsProperty(T value, quint64 timestamp){
            m_data = value;
            m_timestamp = timestamp;
        }
        AwsProperty(){}
        T value(){return m_data;}
        void update(T value,quint64 timestamp){m_data = value; m_timestamp = timestamp;}
        quint64 timestamp(){return m_timestamp;}
    
        void toQDataStream(QDataStream &dstream) const {dstream << m_data << m_timestamp;}
        void fromQDataStream(QDataStream &dstream){dstream >> m_data >> m_timestamp;}
    private:
        quint64 m_timestamp;
        T m_data;
    };
    
    template <typename T>
    QDataStream& operator<<(QDataStream& out, const AwsProperty<T>& classObj) {
        classObj.toQDataStream(out);
        return out;
    }
    
    template <typename T>
    QDataStream& operator>>(QDataStream& in, AwsProperty<T>& classObj) {
        classObj.fromQDataStream(in);
        return in;
    }
    
    typedef AwsProperty<qint32> AwsPropertyInt32;
    Q_DECLARE_METATYPE(AwsPropertyInt32)
    typedef AwsProperty<quint32> AwsPropertyUint32;
    Q_DECLARE_METATYPE(AwsPropertyUint32)
    typedef AwsProperty<bool> AwsPropertyBool;
    Q_DECLARE_METATYPE(AwsPropertyBool)
    

    main.cpp

    #include "awsproperty.h"
    #include <QSettings>
    #include <QDebug>
    
    int main(int argc, char *argv[])
    {
        qRegisterMetaTypeStreamOperators<AwsPropertyInt32>("AwsPropertyInt32");
        qRegisterMetaTypeStreamOperators<AwsPropertyUint32>("AwsPropertyUint32");
        qRegisterMetaTypeStreamOperators<AwsPropertyBool>("AwsPropertyBool");
        QSettings set("/tmp/testsettings.conf");
    
        AwsPropertyInt32 a{-2, 100};
        set.setValue("property", QVariant::fromValue(a));
        auto val = set.value("property").value<AwsPropertyInt32>();
        qDebug() << val.value() << " " << val.timestamp();
    }