13,046,474 members (73,155 online)
alternative version

#### Stats

57.5K views
12 bookmarked
Posted 28 May 2005

# Declutter your loops ... Replacing for with for_each

, 28 May 2005
 Rate this:
How to use the STL for_each algorithm to implement loops and why it's a good idea to do so.

## Introduction

How many times have you read about the merits of using the STL algorithms instead of hand written loops? Chances are this is something that you have heard a lot. The thing is, actually being able to achieve this in real world programs is not very intuitive; especially if you are new to the STL. However, once you learn how the STL algorithms interact with your code, using `for_each` becomes easy. In fact, it becomes so easy and it is so powerful, that you may never write another loop in your career.

## The for_each algorithm

The `for_each` algorithm iterates over a container and “does something” for each element in the container. As a programmer, you have to specify what you want to be done for each element when you call the `for_each` algorithm. You do this by providing a function which the algorithm calls as it iterates over the container.

The algorithm is not a magic. It does what you think it does. So let’s take a look at the implementation of `for_each` that comes with Microsoft’s C++ 7:

```/*
*/
// TEMPLATE FUNCTION for_each
template<class _InIt, class _Fn1> inline
_Fn1 for_each(_InIt _First, _InIt _Last, _Fn1 _Func)
{
// perform function for each element
for (; _First != _Last; ++_First)
_Func(*_First);
return (_Func);
}```

As you can see, the algorithm iterates over the range passed in and invokes a function for each element in the range.

The general idea while replacing loops with `for_each` is that you write a function implementing the loop logic, that is, what you want to do for each iteration of the loop. You then supply this function as the third parameter (`_Func`) to the `for_each` algorithm. Sounds good? Well, I’m afraid that there’s a little more to it than that.

Notice that the signature of the function called by `for_each` is fixed. It has to be a function taking just one parameter and this parameter has to be of the same type as the elements in the container. So if you write a function implementing your loop logic, the only parameter it can have is the current element in the loop; and herein lays the problem.

What if you want to have more that one parameter?

## Use function objects to build logic hierarchies

Let’s take a specific example. Say that we are looping over a vector `<wstring>` and we want to compare each `<wstring>` in the vector to an external `wstring` object and write it out to a file if they are the same.

Without using `for_each`, our code would look something like the following:

```wstring wstrTarget;
wstring wstrFile;
for ( vector<wstring>::iterator itr = vec.begin(); itr != vec.end(); itr++ )
{
if ( *itr == wstrTarget )
writeToFile( *itr, wstrFile );
}```

How would we do the same thing using `for_each`? Well, we need a function that can compare the current element to `wstrTarget` and, if they match, write the current element out to the file called `wstrFile`. So, the function needs to know three things: the current element, what to match it to and the name of the file to write to. But how do we tell the function these three things? Remember that we can only supply the function with one parameter, the current element, so how do we get the other pieces of information into the function?

The answer lies in the function objects.

Because function objects can be called like functions, we can use one as the function passed into `for_each`. That is, in the `for_each` implementation given above, `_Func(*_First)` can call a function object as well as a function. Also, because function objects are objects (like any other) they can have properties, methods and constructors. This allows us to supply the function object with the additional data it needs to perform the loop logic which cannot be supplied automatically by the `for_each` algorithm.

A convenient and concise way of doing this is by supplying the extra data in the constructor of the function object.

In our example, we can define a function object called `compareAndWrite` which accepts the target `wstring` object and the file name to write to in its constructor. Defining an `operator()` accepting a <CODE lang=c++>const wstring& as a parameter allows the function object to be used by the `for_each` algorithm and receive the current element from each iteration.

Putting all the pieces together, we get the following definition for the `compareAndWrite` function object:

```struct compareAndWrite
{
const wstring& wstrTarget;
const wstring& wstrFile;

compareAndWrite(
const wstring& wstrT,
const wstring& wstrF
) : wstrTarget(wstrT), wstrFile(wstrF)
{
}

void operator()( const wstring& val )
{
if ( val == wstrTarget )
writeToFile( val, wstrFile );
}

};```

which allows us to replace the hand crafted `for` loop with the following call to `for_each`.

`for_each( vec.begin(), vec.end(), compareAndWrite(wstrTarget,wstrFile) );`

## Why is this better?

OK, so we have to write more code to use function objects, but the extra code is worth writing and here’s why.

The extra code is required to define the function object. We have to define the class structure, methods and variables. Once we have the class defined, the actual loop logic is really not too different at all and is defined by the class’s `operator()`.

So why bother using the `for_each` algorithm when more code is required?

Well, with hand crafted loops, how do you:

• use the same loop in multiple places?
• have multiple loops that share some common logic but do different things?

Reusing a loop without function objects invariably involves making a new copy of the loop code. This is not good. You now have two copies of the same code in two different parts of your software.

Building a slightly different version of the loop will also normally involve taking a copy of the code and modifying the loop logic. Again, you now have two chunks of code doing similar things that have to be maintained.

Function objects and the `for_each` algorithm give you the ability to build your loop logic as a fully fledged class and reap all the benefits that come from inheritance, polymorphism and encapsulation.

You can build a class hierarchy defining the different versions of your loop logic without having to maintain multiple copies of the same code or complicate the loop logic with parameterization (as would be the case if you defined the loop logic in a function rather than a function object).

So, in this example, to use a slightly different version of the `compareAndWrite` loop, all we need to do is define a subclass of the `compareAndWrite` function object and use that in the call to `for_each`.

```struct multiCompareAndWrite :
public compareAndWrite
{
// loop logic here
};
for_each(vec.begin(), vec.end(),
multiCompareAndWrite(wstrTarget,wstrFile));```

## Other benefits

• Simpler logic

In loops, typically there are variables that change and variables that remain constant. Using the function object and `for_each` technique allows the programmer to define what variables remain constant for the loop and those that do not. The additional data that is required by the loop logic is supplied in the function object’s constructor. The data that is not changed by the loop logic is declared as <CODE lang=c++>const in the function object. That way, any programmer reading your code can immediately see what data is changed and what data is not changed by the loop logic.

In order to figure out what a hand crafted loop does, you need to read the code. However, well named function objects, like `compareAndWrite`, `addRecToDatabase` etc. convey what they do in their names.

For example, it is obvious what the following statement does without any explanation or delving into the code.

`for_each(vec.begin(), vec.end(), addRecToDatabase(connectString));`

## Summary

Replacing <CODE lang=c++>for loops with the STL `for_each` algorithm is a great way of making object oriented programming work for you. You can avoid having multiple copies of the same or similar code to maintain by building class hierarchies of loop logic. What’s more, your code becomes less cluttered, easier to read and more componentized.

The key aspects of this technique are:

• Create function objects that implement and encapsulate your loop logic.
• Pass any additional data required by the loop logic into the constructor of the function object.
• If any of the additional data is not changed by the loop logic, make it <CODE lang=c++>const in the function object.
• Build class hierarchies of loop logic function objects to maximize the reuse and robustness of your software.

A list of licenses authors might use can be found here

## Share

 Web Developer United Kingdom
I work as Software Development Manager for XLCubed, a Business Intelligence vendor. My technical interests are generic C++, algorithms, data analysis and software design.

## You may also be interested in...

 First Prev Next
 communication gagaro24-Sep-06 18:53 gagaro 24-Sep-06 18:53
 You Drank the Kool Aid drudru1-Jun-05 19:34 drudru 1-Jun-05 19:34
 Re: You Drank the Kool Aid Frast2-Jun-05 6:20 Frast 2-Jun-05 6:20
 Re: You Drank the Kool Aid Don Clugston5-Jun-05 16:24 Don Clugston 5-Jun-05 16:24
 Re: You Drank the Kool Aid CP Visitor7-Jun-05 2:02 CP Visitor 7-Jun-05 2:02
 Re: You Drank the Kool Aid Don Clugston5-Jun-05 16:25 Don Clugston 5-Jun-05 16:25
 Re: You Drank the Kool Aid Zac Howland18-May-06 6:53 Zac Howland 18-May-06 6:53
 Unfortunately, that's not all Don Clugston29-May-05 16:22 Don Clugston 29-May-05 16:22
 Re: Unfortunately, that's not all Roland Pibinger29-May-05 23:16 Roland Pibinger 29-May-05 23:16
 Re: Unfortunately, that's not all Martin Friedrich1-Jun-05 20:59 Martin Friedrich 1-Jun-05 20:59
 Re: Unfortunately, that's not all Gabhan Berry1-Jun-05 23:46 Gabhan Berry 1-Jun-05 23:46
 Re: Unfortunately, that's not all Tanveer Badar1-Jun-05 6:50 Tanveer Badar 1-Jun-05 6:50
 Re: Unfortunately, that's not all Zac Howland18-May-06 6:56 Zac Howland 18-May-06 6:56
 Re: Unfortunately, that's not all Gabhan Berry1-Jun-05 23:32 Gabhan Berry 1-Jun-05 23:32
 Re: Unfortunately, that's not all ~louis17-Feb-07 5:23 ~louis 17-Feb-07 5:23
 Re: Unfortunately, that's not all LBRODY24-Jun-05 18:57 LBRODY2 4-Jun-05 18:57
 Last Visit: 31-Dec-99 18:00     Last Update: 23-Jul-17 14:12 Refresh 1