Beginner's Guide

# Function ObjectsFunction ObjectsFunction Objects

``````#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 ^``````

## Example: Interval QueryExample: in_intervalExample

``````#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:
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
}``````

### Finding in IntervalsFind ``````#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:
bool operator () (int x) const noexcept {
return x >= a_ && x <= b_;
}
};

int main () {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 value = *i;  // int value = 8
auto index = distance(begin(v),i);  // int index = 5
…
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 = 2
auto index = distance(begin(v),j);  // int index = 1
…
std::cout << "value: " << value << '\n';
std::cout << "index: " << index << '\n';}
}``````

### Partitioning with IntervalsPartition 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:
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';
}``````

## 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., 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.

## Standard Library Function ObjectsStandard Function ObjectsStd.Lib.

### Comparisons

• `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
}``````

### Arithmetic OperationsArithmetic

• `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<>{}` 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';
}``````