tags:

views:

396

answers:

7

A common pattern with STL containers is this:

map<Key, Value> map;
for(map<Key, Value>::iterator iter = map.begin(); iter != map.end(); ++iter)
{
  ...
}

So inorder to avoid writing the decleration of the template parameters we can do this somewhere:

typedef map<Key, Value> TNiceNameForAMap;

But if this map is only used in a single function or for a single iteration this is an annoying overhead.
Is there any way around this typedef?

+10  A: 

Not sure what you mean by "overhead". If it simplifies the way you write your code, use it, otherwise stick with the longhand.

If it's only used in a restricted scope, put the typedef in that same scope. Then it doesn't need to be published, or documented, or appear on any UML diagrams. For example (and I don't claim this is the best code ever in other respects):

int totalSize() {
    typedef std::map<Key, Value> DeDuplicator;
    DeDuplicator everything;

    // Run around the universe finding everything. If we encounter a key
    // more than once it's only added once.

    // now compute the total
    int total = 0;
    for(DeDuplicator::iterator i = everything.begin(); i <= everything.end(); ++i) {
        total += i->second.size(); // yeah, yeah, overflow. Whatever.
    }
    return total;
}

Combining with Ferruccio's suggestion (if you're using boost), the loop becomes:

BOOST_FOREACH(DeDuplicator::pair p, everything) {
    total += p.second.size();
}

And combining with bk1e's suggestion (if you're using C++0x or have features from it), and assuming that BOOST_FOREACH interacts with auto in the way I think it should based on the fact that it can normally handle implicit casts to compatible types:

std::map<Key, Value> everything;
// snipped code to run around...
int total = 0;
BOOST_FOREACH(auto p, everything) {
    total += p.second.size();
}

Not bad.

Steve Jessop
Well-done ! Your last one is up to Python's level in compacity *and* readability.
rlerallut
And might even run faster.
Steve Jessop
+5  A: 

You can use Boost.Foreach

Ferruccio
Good call, since the loop verbosity is greater than the typedef verbosity anyway...
Steve Jessop
Ferruccio
+2  A: 

Personally I think MYMAP::iterator is more readable than map<int,string>::iterator or even std::map<int, std::string>::iterator so I always do the typedef. The only overhead is one line of code.

Once the code is compiled, there will be no difference in the size or speed of the executable. It's just about readability.

Adam Pierce
+2  A: 

A future version of the C++ standard (known as C++0x) will introduce a new use for the auto keyword, allowing you to write something like the following:

map<Key, Value> map;
for(auto iter = map.begin(); iter != map.end(); ++iter)
{
  ...
}
bk1e
Woohoo! Strong typing like it oughta be.
Steve Jessop
A: 

If the typedef is local to a single function it doesn't even need to be a nice name. Use X or MAP, just like in a template.

Zan Lynx
Variables don't need to have nice names either. But it's nice if they do ;-)
Steve Jessop
A: 

C++0x will also offer ranged-based for loop, which is similar to iterative for looping in other languages.

Unfortunately, GCC does not yet implement range-based for (but does implement auto).

Edit: In the meanwhile, also consider typedefing the iterator. It doesn't get around the one-use typedef (unless you put that in a header, which is always an option), but it makes the resulting code shorter by one ::iterator.

coppro
A: 

Over the past few years I've really tried to move away from using manually written loops in preference to using the STL algorithms. Your above code can be changed to:

struct DoLoopBody {
  template <typename ValueType>
  inline void operator()(ValueType v) const {
    // ...
  }
};

std::for_each (map.begin(), map.end(), DoLoopBody ());

Unfortunately the class DoLoopBody cannot be a local class, which is often highlighted as a disadvantage. However, I see this as an advantage in that the body of the loop can now be unit tested in isolation.

Richard Corden
The trouble with that (and I'm not blaming your use of it, I'm blaming STL) is that it isn't really a foreach loop, because you specify the start and end conditions. It's more like perl's .. range operator.
Steve Jessop
Also note that the future standard C++0x will include something that looks like lambda functions, which will make code more compact (not easier to read, though, IMHO). Good point about testing the body of the loop in isolation.
rlerallut