Question

I have a 'foreach' macro I use frequently in C++ that works for most STL containers:

#define foreach(var, container) \
  for(typeof((container).begin()) var = (container).begin(); \
      var != (container).end(); \
      ++var)

(Note that 'typeof' is a gcc extension.) It is used like this:

std::vector< Blorgus > blorgi = ...;
foreach(blorgus, blorgi) {
  blorgus->draw();
}

I would like to make something similar that iterates over a map's values. Call it "foreach_value", perhaps. So instead of writing

foreach(pair, mymap) {
  pair->second->foo();
}

I would write

foreach_value(v, mymap) {
  v.foo();
}

I can't come up with a macro that will do this, because it requires declaring two variables: the iterator and the value variable ('v', above). I don't know how to do that in the initializer of a for loop, even using gcc extensions. I could declare it just before the foreach_value call, but then it will conflict with other instances of the foreach_value macro in the same scope. If I could suffix the current line number to the iterator variable name, it would work, but I don't know how to do that.

Was it helpful?

Solution

You can do this using two loops. The first declares the iterator, with a name which is a function of the container variable (and you can make this uglier if you're worried about conflicts with your own code). The second declares the value variable.

#define ci(container) container ## iter
#define foreach_value(var, container) \
    for (typeof((container).begin()) ci(container) = container.begin(); \
         ci(container) != container.end(); ) \
        for (typeof(ci(container)->second)* var = &ci(container)->second; \
             ci(container) != container.end(); \
             (++ci(container) != container.end()) ? \
                 (var = &ci(container)->second) : var)

By using the same loop termination condition, the outer loop only happens once (and if you're lucky, gets optimized away). Also, you avoid calling ->second on the iterator if the map is empty. That's the same reason for the ternary operator in the increment of the inner loop; at the end, we just leave var at the last value, since it won't be referenced again.

You could inline ci(container), but I think it makes the macro more readable.

OTHER TIPS

You would be looking for BOOST_FOREACH - they have done all the work for you already!

If you do want to roll your own, you can declare a block anywhere in C++, which resolves your scope issue with your intermediate storage of itr->second ...

// Valid C++ code (which does nothing useful)
{
  int a = 21; // Which could be storage of your value type
}
// a out of scope here
{ 
  int a = 32; // Does not conflict with a above
}

The STL transform function also does something similar.

The arguments are (in order):

  1. An input iterator designating the beginning of a container
  2. An input iterator designating the end of the container
  3. An output iterator defining where to put the output (for an in-place transform, similar to for-each, just pass the the input iterator in #1)
  4. A unary function (function object) to perform on each element

For a very simple example, you could capitalize each character in a string by:

#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>

int main(int argc, char* argv[]) {
    std::string s("my lowercase string");
    std::transform(s.begin(), s.end(), s.begin(), toupper);
    std::cout << s << std::endl; // "MY LOWERCASE STRING"
}

Alternatively there is also the accumulate function, which allows some values to be retained between calls to the function object. accumulate does not modify the data in the input container as is the case with transform.

Have you thought of using the Boost libraries? They have a foreach macro implemented which is probably more robust than anything you'll write... and there is also transform_iterator which would seem to be able to be used to do the second-extraction part of what you want.

Unfortunately I can't tell you exactly how to use it because I don't know enough C++ :) This Google search turns up some promising answers: comp.lang.c++.moderated, Boost transform_iterator use case.

Boost::For_each is by far your best bet. The nifty thing is that what they actually give you is the macro BOOST_FOREACH() which you can then wrap and #define to whatever you would really like to call it in your code. Most everyone will opt for the good old "foreach", but other shops may have different coding standards, so this fits with that mindset. Boost also has lots of other goodies for C++ developers! Well worth using.

I created a little Foreach.h helper with a few variants of foreach() including both ones operating on the local variables and on pointers, with also an extra version secured against deleting elements from within loop. So the code that uses my macros looks nice and cozy like this:

#include <cstdio>
#include <vector>
#include "foreach.h"

int main()
{
    // make int vector and fill it
    vector<int> k;
    for (int i=0; i<10; ++i) k.push_back(i);

    // show what the upper loop filled
    foreach_ (it, k) printf("%i ",(*it));
    printf("\n");

    // show all of the data, but get rid of 4
    // http://en.wikipedia.org/wiki/Tetraphobia :)
    foreachdel_ (it, k)
    {
        if (*it == 4) it=k.erase(it);
        printf("%i ",(*it));
    }
    printf("\n");

    return 0;
}

output:

0 1 2 3 4 5 6 7 8 9
0 1 2 3 5 6 7 8 9

My Foreach.h provides following macros:

  • foreach() - regular foreach for pointers
  • foreach_() - regular foreach for local variables
  • foreachdel() - foreach version with checks for deletion within loop, pointer version
  • foreachdel_() - foreach version with checks for deletion within loop, local variable version

They sure do work for me, I hope they will also make your life a bit easier :)

There are two parts to this question. You need to somehow (1) generate an iterator (or rather, an iterable sequence) over you map's values (not keys), and (2) use a macro to do the iteration without a lot of boilerplate.

The cleanest solution is to use a Boost Range Adaptor for part (1) and Boost Foreach for part (2). You don't need to write the macro or implement the iterator yourself.

#include <map>
#include <string>
#include <boost/range/adaptor/map.hpp>
#include <boost/foreach.hpp>

int main()
{
    // Sample data
    std::map<int, std::string> myMap ;
    myMap[0] = "Zero" ;
    myMap[10] = "Ten" ;
    myMap[20] = "Twenty" ;

    // Loop over map values
    BOOST_FOREACH( std::string text, myMap | boost::adaptors::map_values )
    {
        std::cout << text << " " ;
    }
}
// Output:
// Zero Ten Twenty

You could define a template class that takes the type of mymap as a template parameter, and acts like an iterator over the values by overloading * and ->.

#define foreach(var, container) for (typeof((container).begin()) var = (container).begin(); var != (container).end(); ++var)

There's no typeof in C++... how is this compiling for you? (it's certainly not portable)

I implemented my own foreach_value based on the Boost foreach code:

#include <boost/preprocessor/cat.hpp>
#define MUNZEKONZA_FOREACH_IN_MAP_ID(x)  BOOST_PP_CAT(x, __LINE__)

namespace munzekonza {
namespace foreach_in_map_private {
inline bool set_false(bool& b) {
  b = false;
  return false;
}

}
}

#define MUNZEKONZA_FOREACH_VALUE(value, map)                                  \
for(auto MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_it) = map.begin();      \
        MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_it) != map.end();)       \
for(bool MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_continue) = true;       \
      MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_continue) &&               \
      MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_it) != map.end();          \
      (MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_continue)) ?              \
        ((void)++MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_it)) :          \
        (void)0)                                                              \
  if( munzekonza::foreach_in_map_private::set_false(                          \
          MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_continue))) {} else    \
  for( value = MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_it)->second;      \
        !MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_continue);              \
        MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_continue) = true)        

For example, you can use it in your code like this:

#define MUNZEKONZA_FOREACH_VALUE foreach_value

std::map<int, std::string> mymap;
// populate the map ...

foreach_value( const std::string& value, mymap ) {
  // do something with value
}

// change value
foreach_value( std::string& value, mymap ) {
  value = "hey";
}
#define zforeach(var, container) for(auto var = (container).begin(); var != (container).end(); ++var)

there is no typeof() so you can use this:

decltype((container).begin()) var 
decltype(container)::iterator var
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top