About std::for_each

Few weeks ago I promised to whine some more about std::for_each. _In many C++ books and articles it’s presented as an ultimate loop solution. Typical example is some _for _loop, which is later replaced with for_each form. Funny thing is, even there, in many cases the latter piece of code is 2-3 times longer than the original. Is it worth the hassle? Typical example, taken from here (this is randomly chosen article, no hard feelings):

for’ version:

1wstring wstrTarget;
2wstring wstrFile;
3for ( vector::iterator itr = vec.begin(); itr != vec.end(); itr++ )
4{
5    if ( *itr == wstrTarget )
6        writeToFile( *itr, wstrFile );
7}

Same functionality, uses for_each:

 1struct compareAndWrite
 2{
 3    const wstring& wstrTarget;
 4    const wstring& wstrFile;
 5
 6    compareAndWrite(
 7        const wstring& wstrT,
 8        const wstring& wstrF
 9        ) : wstrTarget(wstrT), wstrFile(wstrF)
10    {
11    }
12
13    void operator()( const wstring& val )
14    {
15        if ( val == wstrTarget )
16            writeToFile( val, wstrFile );
17    }
18};
19...
20for_each(vec.begin(), vec.end(),
21    compareAndWrite(wstrTarget,wstrFile));

Now, bear in mind, it’s actually one of the rather reasonable examples. I’ve seen snippets where the difference in code size has been much bigger than here. Author realizes this as well and gives the ‘holy’ justification: we can reuse the loop now. Sounds cool. However, let’s honestly ask ourselves: how often do we actually reuse loop bodies? In 90% of cases it’s the function that contains the loop that matters, not the loop itself. Is it really good idea to introduce 15 lines of code and new structure just because maybe, just maybe, one day we’ll be able to use it in some other place? Wouldnt it be better to start with simple loop version and when at some point in the future the need arises - introduce for_each? It’s a shame that C++ lacks true lambda support, it would actually make the “standard” solution much more viable. There’s boost::lambda, but it looks a bit like using a heavy cannon to kill a fly.

Using for loop with iterators is not very convenient. There are several alternatives. One’s already mentioned, but as I wrote - I only use it in very special cases. Another is BOOST_FOR_EACH by Eric Niebler (see this article for more info). In our case the loop would look like:

1wstring wstrFile;
2BOOST_FOR_EACH(const wstring& wstr, vec)
3{
4    if (wstr == wstrTarget)
5        writeToFile(wstr, wstrFile);
6}

The problem with this approach is that it’s not really that light weight, it pulls in at least dozen of headers. If you’re working under latest MSVC and do not plan to port your code on other platforms you can use its built-in ‘for each’ extension:

1wstring wstrFile;
2for each (const wstring& wstr in vec)
3{
4    if (wstr == wstrTarget)
5        writeToFile(wstr, wstrFile);
6}

It looks the most elegant, but sadly is a big no-no in multi-platform codebases.

In my code I use:

  • for_each if I can use STL functor/adaptor (it still is dangerous, because it doesnt ‘scale’ too good), I already have functor ready or I can actually reuse the loop body

  • BOOST_FOR_EACH almost everywhere else (sadly it doesnt seem to work with associative containers).

Old comments

SirMike 2008-04-10 20:04:36

Every attempt to make C++ language a functional language, ends with very ugly code.
What about this? ;)
http://www.sirmike.org/2007/11/17/vomit-c/

More Reading
Newer// BASS2?