Pointer to function, functor, lambda function

Let's see an example where the use of pointer to function, functor, or lambda function is just a matter of personal taste. I'm assuming you are working with a modern C++ compiler and you don't have any special constrain.

We have an array of doubles, and we want to know how many values in there satisfy a given condition, that could vary. To do that, we want to call the STL function count_if(), using a predicate that we can select accordingly to the user request.

We'll do some test on this data:
double values[] = { 41.97, 12.34, 95.43, 9, 44.51 };
const int SIZE = sizeof(values) / sizeof(double);
And we want just to count how many elements are less than 42.

Pointer to function

The STL count_if() function expects as input the delimiters for the sequence it has to operate on, and a predicate accepting in input a value, matching the collection base type, and returning a boolean. We can think to implement a first rough solution like this:
bool isLessThan42(double value) { return value < 42; }
// ...
std::cout << std::count_if(values, values + SIZE, isLessThan42) << std::endl;
The most painful limitation of this implementation is that the comparator is too inflexible. But we can easily relax it using a binder.

Pointer to function with STL binder

We had a problem in the first implementation, count_if() asks for a one-parameter function, but we want to use a two-parameter one. No problem, we can adapt our function:
bool isLessThan(double value, double limit)
{
    return value < limit;
}
// ...
const double LIMIT = 42;
std::cout << std::count_if(values, values + SIZE, std::bind(isLessThan, std::placeholders::_1, LIMIT)) << std::endl;
The STL bind adapter connects our isLessThan() function to count_if, using as first parameter (first placeholder) the one provided by count_if and adding LIMIT in the second place.

Functor

The second pointer to function implementation works fine, but why passing each time the limit for comparison? Wouldn't be enough to pass it once, and use it for all the iteration? We can do it using a functor:
class LessThan : public std::unary_function<double, bool> // 1
{
private:
    argument_type limit_;
public:
    LessThan(argument_type limit) : limit_(limit) {}
    result_type operator() (argument_type value) { return value < limit_; }
};
// ...
const double LIMIT = 42;
std::cout << std::count_if(values, values + SIZE, LessThan(LIMIT)) << std::endl; // 2
1. unary_function is an STL utility class provided to help keeping consistence for the creating (unary) functors. It is not mandatory to use it, but it is a good idea, even just for documentation. Reading the class header is enough to see that LessThan is a functor that gets in input a double (argument_type) and returns a boolean (result_type).
2. A LessThan object is created passing LIMIT to its ctor, and then passed to count_if(). Each iteration of count_if() calls the LessThan operator() function.

C++11 lambda

If your compiler implements the 2011 C++ standard lambda function, you could simplify the code in this way:
const double LIMIT = 42;
std::cout << std::count_if(values, values + SIZE, [LIMIT](double value){ return value < LIMIT; }) << std::endl;
The access to the LIMIT constant is granted to the lambda function body putting it in the capture section.

Boost lambda

If your compiler does not implement the standard C++ lambda, you could still use it through the Boost Libraries support:
std::cout << "Boost lambda: " << std::count_if(values, values + SIZE, boost::lambda::_1 < LIMIT ) << std::endl;
STL Functor

In such a simple case, is probably not worthy to create a custom functor. We could use a standard one, and adapt it to do it what we want. In this case, we have a ready made less<> functor (better categorized as an adaptable binary predicate) that could do:
std::cout << std::count_if(values, values + SIZE, std::bind2nd(std::less<double>(), LIMIT)) << std::endl;

No comments:

Post a Comment