Iterating over a QMap with for
I've a QMap
object and I am trying to write its content to a file.
QMap<QString, QString> extensions;
//..
for(auto e : extensions)
{
fout << e.first << "," << e.second << '\n';
}
Why do I get: error: 'class QString' has no member named 'first' nor 'second'
Is e
not of type QPair
?
Solution 1:
If you want the STL style with first
and second
, do this:
for(auto e : extensions.toStdMap())
{
fout << e.first << "," << e.second << '\n';
}
If you want to use what Qt offers, do this:
for(auto e : extensions.keys())
{
fout << e << "," << extensions.value(e) << '\n';
}
Solution 2:
C++11 range-based-for uses the type of the dereferenced iterator as the automatically deduced "cursor" type. Here, it is the type of the expression *map.begin()
.
And since QMap::iterator::operator*()
returns a reference to the value (of type QString &
), the key isn't accessible using that method.
You should use one of the iterator methods described in the documentation but you should avoid using
-
keys()
because it involves creating a list of keys and then searching the value for each key, or, -
toStdMap()
because it copies all the map elements to another one,
and that wouldn't be very optimal.
You could also use a wrapper to get
QMap::iterator
as the auto
type:
template<class Map>
struct RangeWrapper {
typedef typename Map::iterator MapIterator;
Map ↦
RangeWrapper(Map & map_) : map(map_) {}
struct iterator {
MapIterator mapIterator;
iterator(const MapIterator &mapIterator_): mapIterator(mapIterator_) {}
MapIterator operator*() {
return mapIterator;
}
iterator & operator++() {
++mapIterator;
return *this;
}
bool operator!=(const iterator & other) {
return this->mapIterator != other.mapIterator;
}
};
iterator begin() {
return map.begin();
}
iterator end() {
return map.end();
}
};
// Function to be able to use automatic template type deduction
template<class Map>
RangeWrapper<Map> toRange(Map & map)
{
return RangeWrapper<Map>(map);
}
// Usage code
QMap<QString, QString> extensions;
...
for(auto e : toRange(extensions)) {
fout << e.key() << "," << e.value() << '\n';
}
There is another wrapper here.