HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Qt foreach-like alternative to iterate over value AND key of an associative container

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
alternativecontainerandlikevalueiterateforeachoverassociativekey

Problem

The Qt documentation recommend an iterator-based solution to iterate over an associative container like QMap and QHash, and I always wondered if there really isn't a (nice) solution using a foreach loop like in PHP:

foreach($container as $key => $value)


I looked into the source code of the foreach macro and extended it by a key variable. The following code is only the GCC version of the loop (it doesn't work with all compilers, see Q_FOREACH macro definition in qglobal.h for other versions).

#define foreachkv(keyvar, variable, container) \
for (QForeachContainer _container_(container); \
!_container_.brk && _container_.i != _container_.e; \
__extension__ ({ ++_container_.brk; ++_container_.i; })) \
for (keyvar = _container_.i.key();; __extension__ ({break;})) \
for (variable = *_container_.i;; __extension__ ({--_container_.brk; break;}))


Now you can do the following:

QVariantHash m;
m.insert("test", 42);
m.insert("foo", true);
foreachkv(QString k, QVariant v, m)
qDebug() "

The output will be:

"foo" => QVariant(bool, true)
"test" => QVariant(int, 42)


Tests I've done so far:

  • examples from above



  • foreachkv works as expected with break and continue statements within the loop.



What did I do? I just added another for loop to introduce the key variable (called
keyvar` in the macro). Maybe I don't need this loop?

Solution

You can probably do something simpler to avoid making this a special case macro, e.g. using std::tie or boost::tie if that's not available:

#include 
#include 
#include 
#include 

int main() {
  std::map map = {std::make_pair(1,"one"), std::make_pair(2,"two")};
  int k;
  std::string v;
  BOOST_FOREACH(std::tie(k, v), map) {
    std::cout << "k=" << k << " - " << v << std::endl;
  }
}

Code Snippets

#include <map>
#include <functional>
#include <boost/foreach.hpp>
#include <iostream>

int main() {
  std::map<int, std::string> map = {std::make_pair(1,"one"), std::make_pair(2,"two")};
  int k;
  std::string v;
  BOOST_FOREACH(std::tie(k, v), map) {
    std::cout << "k=" << k << " - " << v << std::endl;
  }
}

Context

StackExchange Code Review Q#11681, answer score: 2

Revisions (0)

No revisions yet.