Beginner's Guide

# Function ObjectsFunction ObjectsFunction Objects

``````class Multiplier {
int m_;
public:
// constructor:
explicit constexpr   Multiplier(int m) noexcept : m_{m} {}
// "call operator":
constexpr int   operator () const noexcept (int x) {     return m_ * x;   }
};``````
``````Multiplier triple{3};
int i = triple(2);  // i: 6``````
``````class Accumulator {
int sum_ = 0;
public:
void operator () (int x) noexcept {     sum_ += x;   }
int total() const noexcept { return sum_; }
};
Accumulator acc;
acc(2);
acc(3);
int sum = acc.total();  // sum: 5``````

## Example: Interval QueryExample: in_intervalExample

``````class in_interval {
int a_;
int b_;
public:
// constructor:
explicit constexpr
in_interval(int a, int b):     a_{a}, b_{b} noexcept {}
// call operator:
constexpr bool operator () (int x)   const noexcept {
return x >= a && x <= b;
}
};
// make an object
in_interval test {-10,5};
// invoke its operator()
cout << test(1);   // true
cout << test(5);   // true
cout << test(-12); // false
cout << test(8);   // false``````

### Finding in IntervalsFind ``````std::vector<int> v {5,2,9,1,3,8,5,2,9,0};
// find 1st value in interval [6,8]
// in a subrange of v (as shown in image):
auto i = find_if(begin(v)+2, end(v)+7,                  in_interval{6,8});
if(i != end(v)) {
auto val = *i;    // val: 8
auto idx = distance(begin(v),i); // idx: 3
…
}
// 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 val = *j;    // val: 2
auto idx = distance(begin(v),j); // idx: 1
…
}``````

### Partitioning with IntervalsPartition ``````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 0 2'

// print 2nd partition:
for_each(i, end(v), [](int x){   std::cout << x << ' '; }); // prints '4 6 3 8 5'

auto val = *i;  // val: 4
auto idx = distance(begin(v),i); // idx: 3``````

## Guidelines

### Avoid Stateful `operator()`State

###### 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., to track status information with a parallel standard algorithm, then make sure it is concurrency-safe (i.e., can be accessed from multiple threads simultaniously).