The C++ algorithm library - Draw and Tell pt. II

for_each & for_each_n

The for_each/for_each_n are both close relatives of the for loop. So close that the range base for loop of modern c++ has almost rendered them obsolete.

for_each

The for_each applies a unary function to each of the elements in the range. So if you already have the function (or are going to refactor it out) it is very neat. With a lambda, you basically got a range based for.

#include <algorithm>
#include <vector>
... 

void stream(const Container&);

int main() {  
  std::vector<Container> v = {{0,5},{5,3},{1,4}};

  // for free functions it reads quite well
  std::for_each(std::begin(v), std::end(v), stream);

  // with a member function you get a bit more cruft
  std::for_each(std::begin(v), std::end(v), std::mem_fn(Container::normalize));

  //with the the for_each_n you can apply a function on the n next elements
  std::for_each_n(std::begin(v), 2, stream);

  //and a range based for as a comparison
  for (auto a : v) stream(a);
}
for_each_n

The for_each_n doesn't work on a pair of iterators like most of the algorithms in <algorithm>, but belong to a small subset that use a single iterator and a size (which all end with _n). It will apply the a given (unary) function on the n element starting at the iterator.

Return value

Yes, that is true, the algorithms actually return something. It returns the function or function object back to you. If it is possible to move it, it will be moved. So you can do things like this:

... 

class Counter {  
public:  
  Counter() : dots_total(0) {}
  void operator()(const LadyBug& bug) {dots_total += bug.dots;}
  long dots_total;
};

int main() {  
  std::vector<LadyBug> bugs = get_ladybugs();

  auto count = std::for_each(std::begin(bugs), std::end(bugs), Counter());
  ladybug_dots = count.dots_total;
}

So if your function object has side effects, or is simply very expensive to create, you may have your object back afterwards.

for_each VS range based for

Even though the range based for beats for_each in verbosity there are still some arguments for using the for_each and for_each_n

Why?

One is expressiveness, the for_each variants tell the reader that you intend to call a function for each and every element in the range.

If you have c++17 available another feature is the ability to select execution policy - enabling parallel execution.

And the final and perhaps best reason is that you might limit the range to less than the whole vector.

Can it blow up?

It depends, as usual no algorithms like invalid ranges.

Exceptions

If the unary function throws, the for_each algorithms will throw this right back at you.