I’ve found some good examples of functors on SO like this one, and all the convincing examples seem to use state in the class that defines operator().
I came across an example in a book that defines the function call operator without having state, and I can’t help but feel like this is an awkward usage, and that a normal style function pointer, would be better than using operator() in every way here – less code, less variables (you have to instantiate the comparators), its probably more efficient due to the instantiation, and no loss of meaning or encapsulation (since it’s just one function).
I know std::sort lets you pick between operator() classes and functions, but I’ve always just used the functions because of the above logic.
What are the reasons why a class might be preferred?
Here’s the example (paraphrased):
class Point2D {
//.. accessors, constructors
int x,y;
};
class HorizComp {
public:
bool operator()(const Point2D& p, const Point2D& q) const
{ return p.getX() < q.getX(); }
};
class VertComp {
public:
bool operator()(const Point2D& p, const Point2D& q) const
{ return p.getY() < q.getY(); }
};
template <typename E, typename C>
void printSmaller(const E& p, const E& q, const C& isLess) {
cout << (isLess(p, q) ? p : q) << endl; // print the smaller of p and q
}
//...
// usage in some function:
Point2D p(1.2, 3.2), q(1.5, 9.2);
HorizComp horizComp;
VertComp vorizComp;
printSmaller(p, q, horizComp);
printSmaller(p, q, vorizComp);
The typical reason is that when you do this:
The template argument for the predicate is the following:
Since the sort function receives a function pointer, it is more difficult for the compiler to inline the predicate use inside
std::sort(). This happens because you could have another functionwhich has the exact same type, meaning the
std::sort()instatiation would be shared between the two predicates. (remember that I said that it makes inlining more difficult, not impossible).In contrast, when you do this:
The compiler generates a unique template instantiation for
std::sort()for each predicate, making it easier to inline the predicate’s definition.