I am trying to serialize an object of std::unordered_map<QString, QString>
and place in QSettings
, which I hope to read back later on. Reading the docs, I need to do 2 things: declare it as a meta type and register stream operators, which I did. Here is a complete example reproducing the error:
#include <QCoreApplication>
#include <QDataStream>
#include <QDebug>
#include <QSettings>
#include <QString>
#include <unordered_map>
namespace std {
template <>
struct hash<QString> {
std::size_t operator()(const QString &s) const noexcept {
return static_cast<std::size_t>(qHash(s));
}
};
} // namespace std
using StrMap = std::unordered_map<QString, QString>;
inline QDataStream &operator<<(QDataStream &out, const StrMap &map) {
for (auto &&elm : map) {
out << elm.first << elm.second;
}
return out;
}
inline QDataStream &operator>>(QDataStream &in, StrMap &map) {
QString key;
QString val;
while (not in.atEnd()) {
in >> key >> val;
map.insert_or_assign(std::move(key), std::move(val));
}
return in;
}
Q_DECLARE_METATYPE(StrMap)
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
qRegisterMetaTypeStreamOperators<StrMap>("StrMap");
{
StrMap map{
{"1", "1"},
{"2", "2"},
{"3", "3"},
{"4", "4"},
};
QSettings settings{"TestOrg", "TestApp"};
QVariant var;
var.setValue(map);
settings.setValue("StrMap", std::move(var));
}
QSettings settings{"TestOrg", "TestApp"};
StrMap map{settings.value("StrMap").value<StrMap>()};
for (auto &&pair : map) {
qDebug() << pair.first << " - " << pair.second << '\n';
}
return a.exec();
}
Here when I read back the map object which I serialized, I get an additional element with empty key and empty value. Output:
"" - ""
"1" - "1"
"2" - "2"
"4" - "4"
"3" - "3"
What am I doing wrong? I never placed that empty element.
Some people are going to point me to "Why is iostream::eof inside a loop condition (i.e. while (!stream.eof())) considered wrong?" post, but the main differences here are, I know exactly how many elements I have placed there, so I won't read after the end, and there is apparently no way to convert QDataStream
objects into bool
implicitly, so I can't do while (in >> key >> val){...}
.