Function Objects

Function Objects

In the previous example, we are passing the address of a function (mult()) into the accumulate() function.

We can instead use a Function Object:

//
//  main.cpp
//  STL Function Objects
//
//  Created by Bryan Higgs on 10/23/24.
//

#include <iostream>
#include <vector>  // For vector
#include <numeric>  // For accumulate()

class Multiply
{
public:
  int operator()(int x, int y) const { return x * y; }
};

int main(int argc, const char * argv[])
{
  int values[] = {2, 3, 5, 7, 11};
  size_t len = sizeof(values)/sizeof(values[0]);
  
  // Initialize vector using pointer iterator
  std::vector<int> v(&values[0], &values[len]);
  
  int product = accumulate(v.begin(), v.end(), 1, Multiply());
  std::cout << "Result: " << product << std::endl;
  
  return 0;
}

… which produces the following:

Result: 2310
Program ended with exit code: 0

A function object, or functor, is any type that implements operator(). This operator is referred to as the call operator or sometimes the application operator. The C++ Standard Library uses function objects primarily as sorting criteria for containers and in algorithms.

Reasons for using a function object instead of an ordinary function include:

  • A function object can carry more potentially useful context than can an ordinary function.
  • A function object’s operator() can be inlined, whereas passing the address of an ordinary function precludes inlining.

STL provides the following function objects:

ArithmeticRelationalLogical
plus<T>equal_to<T>logical_and<T>
minus<T>not_equal_to<T>logical_or<T>
multiplies<T>less<T>logical_not<T>
divides<T>greater<T>
modulus<T>less_equal<T>
negate<T>greater_equal<T>

So, we can modify our code to make use of the STL-provided function object, multiplies<T>:

//
//  main.cpp
//  STL Function Objects
//
//  Created by Bryan Higgs on 10/23/24.
//

#include <iostream>
#include <vector>  // For vector
#include <numeric>  // For accumulate()
#include <functional>   // For multiplies

int main(int argc, const char * argv[])
{
  int values[] = {2, 3, 5, 7, 11};
  size_t len = sizeof(values)/sizeof(values[0]);
  
  // Initialize vector using pointer iterator
  std::vector<int> v(&values[0], &values[len]);
  int product = accumulate(v.begin(), v.end(), 1, 
                           std::multiplies<int>() );
  std::cout << "Result: " << product << std::endl;
  
  return 0;
}

… which produces the same output as before.