Boost logo

Boost :

Subject: [boost] [Foreach] Proposal to simplify using Boost.Foreach with maps
From: Chris Purcell (chris.purcell.39_at_[hidden])
Date: 2009-09-12 13:52:45


As documented in the manual ("Pitfalls"), BOOST_FOREACH is a little
awkward to use with associative containers. I've used the following in
the past to simplify my own code, and wondered if it was suitable to
add to the Boost Foreach library proper.

    std::map<int, int> my_map;
    BOOST_FOREACH_PAIR(int key, int value, my_map)
      std::cout << key << " : " << value << "\n";

The BOOST_FOREACH_PAIR macro is a clone of the BOOST_FOREACH macro
with an extra for loop in it to assign both first and second from each
pair in the map. If either is not wanted, ignore from Boost.Tuples can
be used:

    std::vector<int> values;
    BOOST_FOREACH(boost::tuples::ignore, int value, my_map)
      values.push_back(value);

References can be used just as with BOOST_FOREACH, to create a modifying loop:

    BOOST_FOREACH_PAIR(int key, int& value, my_map)
      value += key;

There are a few alternatives to my solution that I have seen:

(1) Predeclare a pair and use it each time around the loop:

    std::pair<int, int> kv;
    BOOST_FOREACH(kv, my_map)
        std::cout << kv.first << " : " << kv.second << "\n";

  This adds overhead from copying pairs, and does not give meaningful
names to the two halves of the pair. It also has no simple extension
to a mutating loop that I am aware of.

(2) Typedef the value type of the map before the loop, and use .first
and .second:

    typedef std::pair<const int, int> KeyValue;
    BOOST_FOREACH(KeyValue const& kv, my_map)
        std::cout << kv.first << " : " << kv.second << "\n";

  This removes the copying overhead, and is easy to change to a
mutating loop, but still does not meaningfully name the key and value

(3) Use Boost.Tuple's tie to turn the single assignment of
BOOST_FOREACH into a double assignment:

    int key, value;
    BOOST_FOREACH(boost::tie(key, value), my_map)
      std::cout << key << " : " << value << "\n"

  This gives meaningful names, but has copying overhead (albeit not in
this simple example). It also has no simple extension to a mutating
loop that I am aware of.

The key objection to all of these alternatives, from my point of view,
is simply that they are unnecessarily complicated. The new macro is
much cleaner.

Implementation of BOOST_FOREACH_PAIR is simple: turn the innermost
assignment loop of BOOST_FOREACH into a pair of loops, one assigning
key, one value.

Cheers,
Chris Purcell


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk