Re: Point of operator() overloading (no pun intended)
Stick wrote:
I just don't get why you need operator() overloading.
It just seems like there is nothing really gained by it, as the
syntax just looks like a constructor, yet, you could easily just have
a member function do something.
The point of overloading operator() is not that it looks like a constructor,
but that it looks like a function call. Typically that's why it's
overloaded: to make an object that behaves like a function.
For example, consider the standard C++ library function std::find_if. It
takes three parameters: a starting iterator, an ending iterator and a
"predicate".
A predicate is anything that "works like a function", takes the required
arguments, and returns bool. So, in the case of std::find_if (for example),
you have quite a lot of flexibility in how you supply the predicate:
#include <algorithm>
bool equals5(int i)
{
return i == 5;
}
template <int n>
struct equals_n
{
bool operator()(int i) const
{
return i == n;
}
};
void f()
{
int a[10];
// put values in a...
// use a function as the predicate
int* p1 = std::find_if(a,a+10,equals5);
// use a function pointer to specify the predicate
bool (*pfn)(int) = equals5;
int* p2 = std::find_if(a,a+10,pfn); // call through a function
pointer
// use an instance of a class as the predicate
int* p3 = std::find_if(a,a+10,equals_n<5>());
}
Note in the last example how an object is being used "like a function".
This is particularly useful in generic code like std::find since it allows
one to wrap up arbitrarily complex, potentially stateful logic into a class
and use it "like a function" - the implementation of std::find niether knows
nor cares.
The legitimate uses for operator() overloading in non-generic code are
fewer, but there are some good examples. Consider a system that evaluates
algebraic equations typed in by the user. Internally, such a system needs
to parse the expression and represent the parsed equation in some kind of
structure (frequently it'll be an "expression tree"). Overloading
operator() on the object that represents a parsed expression that can be
evaluated would be a reasonable design choice.
-cd