Compare
double average = CalculateAverage(values.begin(), values.end());
with
double average = std::for_each(values.begin(), values.end(), CalculateAverage());
What are the benefits of using a functor over a function? Isn’t the first a lot easier to read (even before the implementation is added)?
Assume the functor is defined like this:
class CalculateAverage
{
private:
std::size_t num;
double sum;
public:
CalculateAverage() : num (0) , sum (0)
{
}
void operator () (double elem)
{
num++;
sum += elem;
}
operator double() const
{
return sum / num;
}
};
At least four good reasons:
Separation of concerns
In your particular example, the functor-based approach has the advantage of separating the iteration logic from the average-calculation logic. So you can use your functor in other situations (think about all the other algorithms in the STL), and you can use other functors with
for_each.Parameterisation
You can parameterise a functor more easily. So for instance, you could have a
CalculateAverageOfPowersfunctor that takes the average of the squares, or cubes, etc. of your data, which would be written thus:You could of course do the same thing with a traditional function, but then makes it difficult to use with function pointers, because it has a different prototype to
CalculateAverage.Statefulness
And as functors can be stateful, you could do something like this:
to average across a number of different data-sets.
Note that almost all STL algorithms/containers that accept functors require them to be “pure” predicates, i.e. have no observable change in state over time.
for_eachis a special case in this regard (see e.g. Effective Standard C++ Library – for_each vs. transform).Performance
Functors can often be inlined by the compiler (the STL is a bunch of templates, after all). Whilst the same is theoretically true of functions, compilers typically won’t inline through a function pointer. The canonical example is to compare
std::sortvsqsort; the STL version is often 5-10x faster, assuming the comparison predicate itself is simple.Summary
Of course, it’s possible to emulate the first three with traditional functions and pointers, but it becomes a great deal simpler with functors.