The C++ algorithm library - Draw and Tell

While listening to the CPPCast episode with Sean Parent I heard about his idea about "No raw loops" (which he also talks about here). His explanation is that most loops are already implemented in the algorithm library, and for the loops that aren't we should seek to implement new algorithms instead of adding complex looping constructs into our code.

This lead me to thinking - that might be true, but I simply don't know the algorithm library well enough.

So let me just

#include <algorithm>

and get started

The triplets any_of, all_of and none_of

All algorithms are made to work on a range of elements, and these triplets are not an exception.

They are all in the familiy of non-modifying sequence operations, which in plain english say that none of these algorithms change the data they are working on.

The return value of these algorithms is a bool, and it accepts a range and a unary predicate (A function that accepts the values you are testing and returns true or false)

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

std::vector<Objects> objs = create_objects();  
bool all_good = std::all_of(std::begin(objs), std::end(objs), is_good);  
bool not_bad = std::none_of(std::begin(objs), std::end(objs), is_bad);  
bool any_good = std::any_of(std::begin(objs), std::end(objs), is_good);  
...

The code is almost possible to read as prose:

  • if all of the range is_good return true
  • if none of the range is_bad return true
  • if any of the range is_good return true

So what about empty ranges?

  • all_of: returns true
  • any_of: returns false
  • none_of: returns true

This means that if all_of(..., x()) == true && none_of(..., x()) == true you most probably have a empty range.

Why?

It is for sure more readable than a for-loop equivalent. If that isn't enough for you, most libraries should short circuit the loop increasing the performance if you forgot.

Can I shoot myself in the foot?

Sure, if the range is invalid (like passing in the begin iterator from one container and the end iterator from another) you will have undefined behaviour. Keep sensible and these will serve you good.

Exceptions?

Yes, if your predicates or iterator operations throw so will the algorithm. If you throw, it will throw it right back at you!