◐ Shell
clean mode source ↗

C++ Function Objects Introduction

#include <iostream>

class Multiplier {
  int m_;
public:
  // constructor:
  explicit constexpr   Multiplier (int m) noexcept : m_{m} {}
  // call operator:
  constexpr int   operator () (int x) const noexcept {     return m_ * x;   }
};

int main () {
  Multiplier triple{3};
  int i = triple(2);
  std::cout << "i: " << i << '\n';
}
Multiplier triple{3};
int i = triple(2);  // i: 6
#include <iostream>

class Accumulator {
  int sum_ = 0;
public:
  void operator () (int x) noexcept {     sum_ += x;   }
  int total () const noexcept { return sum_; }
};

int main () {

Accumulator acc; acc(2); acc(3); int sum = acc.total(); // sum: 5 std::cout << "sum: " << sum << '\n'; }
// of, e.g., standard library algorithms:
if ( std::any_of(begin(v), end(v), in_interval{-2,8}) ) 
//            custom function object ^
#include <iostream>

class in_interval {
  int a_;
  int b_;
public:
  // constructor:
  explicit constexpr
  in_interval (int a, int b) noexcept:     a_{a}, b_{b} {}
  // call operator:
  [[nodiscard]] constexpr
  bool operator () (int x) const noexcept {
    return x >= a_ && x <= b_;
  }
};

int main () {

// make an object in_interval test {-10,5}; // invoke its operator() std::cout << test(1) << '\n'; // true std::cout << test(5) << '\n'; // true std::cout << test(-12) << '\n'; // false std::cout << test(8) << '\n'; // false }

standard library algorithm 'find_if' visual example

#include <iostream>
#include <vector>
#include <algorithm>

class in_interval {
  int a_;
  int b_;
public:
  // constructor:
  explicit constexpr
  in_interval(int a, int b) noexcept: a_{a}, b_{b} {}
  // call operator:
  [[nodiscard]] constexpr
  bool operator () (int x) const noexcept {
    return x >= a_ && x <= b_;
  }
};

int main () {
std::vector<int> v {9,0,4,1,8,3,7,2,9};

// find 1st value in interval [6,8] // in a subrange of v (as shown in image): auto i = find_if(begin(v)+2, begin(v)+7, in_interval{6,8}); if (i != end(v)) { auto value = *i; // int value = 8 auto index = distance(begin(v),i); // int index = 4 std::cout << "value: " << value << '\n'; std::cout << "index: " << index << '\n'; std::cout << "-----------------------\n"; }
// find 1st value in [-4,4] in all of v: auto j = find_if(begin(v), end(v), in_interval{-4,4}); if (j != end(v)) { auto value = *j; // int value = 0 auto index = distance(begin(v),j); // int index = 1 std::cout << "value: " << value << '\n'; std::cout << "index: " << index << '\n'; } }

standard library algorithm 'partition2' visual example

Note that the relative order of elements within the resulting partitions need not be the same as in the original sequence.

#include <iostream>
#include <vector>
#include <algorithm>

class in_interval {
  int a_;
  int b_;
public:
  // constructor:
  explicit constexpr
  in_interval(int a, int b) noexcept: a_{a}, b_{b} {}
  // call operator:
  [[nodiscard]] constexpr
  bool operator () (int x) const noexcept {
    return x >= a_ && x <= b_;
  }
};

int main () {
std::vector<int> v {1,4,6,0,2,8,3,5};
auto i = partition(begin(v), end(v),                    in_interval{-1,2});
// print 1st partition:
for_each(begin(v), i, [](int x){   std::cout << x << ' '; }); // prints 1 2 0'
std::cout << '\n';
// print 2nd partition:
for_each(i, end(v), [](int x){   std::cout << x << ' '; }); // prints '6 4 8 3 5'
std::cout << '\n';
auto firstOf2ndPart = *i;  // 6
auto splitIndex = distance(begin(v),i);  // 3
std::cout << "firstOf2ndPart: " << firstOf2ndPart << '\n';
std::cout << "splitIndex:     " << splitIndex << '\n';
}
Stateful = the current result of operator() depends on previous calls of operator()
(e.g., because member variable values are both used for computing the result and changed in the same call to operator())

Many (standard) algorithms do not guarantee any order in which passed-in function objects are called. This is especially the case for the parallel versions of the standard algorithms that were introduced with C++17.

This means passing a stateful function object might yield different results depending on the concrete implementation of a particular algorithm and on the state of the function object prior to passing it to the algorithm.


  • Subsequent calls to operator() should be independent from each other.
  • Prefer to make operator() const, i.e., not alter the function object's state at all.
  • If you do use a non-const operator() (e.g., for tracking status information) with a parallel standard algorithm, then make sure it is concurrency-safe. For example, access to resources that are shared between multiple threads, like e.g., I/O-streams has to be managed properly.
#include <functional>
  • std::equal_to
  • std::not_equal_to
  • std::greater
  • std::less
  • std::greater_equal
  • std::less_equal
  • C++11  must specify operand type explicitly: std::greater<Type>{}
  • C++14  no need for specifying operand type: std::greater<>{}
#include <set>
#include <vector>
#include <functional>
#include <algorithm>
#include <iostream>

int main () {
// set with descending order (default is 'less'):
std::set<int,std::greater<>> s;
// compare with 'greater' instead of the default 'less':
std::vector<int> v1 = {1,4,5};
std::vector<int> v2 = {1,2,5};
std::cout << lexicographical_compare(  begin(v1), end(v1),                                  begin(v2), end(v2), std::greater<>{}) << '\n';  // true
}
#include <functional>
  • std::plus
  • std::minus
  • std::multiplies
  • std::divides
  • std::modulus
  • std::negate
  • C++11  must specify operand type explicitly: std::minus<Type>{}
  • C++14  no need for specifying operand type: std::minus<>{}

Example: Left Fold Using Binary Operation

standard library algorithm 'accumulate' visual example

uses operator + as default, if no fold operation is given as 4th argument ⇒ result is sum of the input elements

#include <vector>
#include <functional>
#include <numeric>
#include <iostream>

int main () {
std::vector<int> v {1,2,3,4,5};
// using default (operator +):
int sum = accumulate(begin(v), end(v), 0);  // sum  15
// using multiplication:
int product = accumulate(begin(v), end(v), 1, std::multiplies<>{});  // product = 120
std::cout << "sum:     " << sum << '\n';
std::cout << "product: " << product << '\n';
}

Last updated: 2022-11-20

Found this useful? Share it: