Why use functors over functions?
Advantages of Functors:
- Unlike Functions Functor can have state.
- Functor fits into OOP paradigm as compared to functions.
- Functor often may be inlined unlike Function pointers
- Functor doesn't require vtable and runtime dispatching, and hence more efficient in most cases.
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 CalculateAverageOfPowers
functor that takes the average of the squares, or cubes, etc. of your data, which would be written thus:
class CalculateAverageOfPowers
{
public:
CalculateAverageOfPowers(float p) : acc(0), n(0), p(p) {}
void operator() (float x) { acc += pow(x, p); n++; }
float getAverage() const { return acc / n; }
private:
float acc;
int n;
float p;
};
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:
CalculateAverage avg;
avg = std::for_each(dataA.begin(), dataA.end(), avg);
avg = std::for_each(dataB.begin(), dataB.end(), avg);
avg = std::for_each(dataC.begin(), dataC.end(), avg);
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_each
is 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::sort
vs qsort
; 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.
std::for_each
is easily the most capricious and least useful of the standard algorithms. It's just a nice wrapper for a loop. However, even it has advantages.
Consider what your first version of CalculateAverage
must look like. It will have a loop over the iterators, and then do stuff with each element. What happens if you write that loop incorrectly? Oops; there's a compiler or runtime error. The second version can never have such errors. Yes, it's not a lot of code, but why do we have to write loops so often? Why not just once?
Now, consider real algorithms; the ones that actually do work. Do you want to write std::sort
? Or std::find
? Or std::nth_element
? Do you even know how to implement it in the most efficient way possible? How many times do you want to implement these complex algorithms?
As for ease of reading, that's in the eyes of the beholder. As I said, std::for_each
is hardly the first choice for algorithms (especially with C++0x's range-based for syntax). But if you're talking about real algorithms, they're very readable; std::sort
sorts a list. Some of the more obscure ones like std::nth_element
won't be as familiar, but you can always look it up in your handy C++ reference.
And even std::for_each is perfectly readable once you use Lambda's in C++0x.