Beginner's Guide
    First Steps
    Input & Output
    Custom Types – Part 1
    Diagnostics
    Standard Library – Part 1
    Function Objects
    Standard Library – Part 2
    Code Organization
    Custom Types – Part 2
    Generic Programming
    Memory Management
    Software Design Basics

    Function Objects Function Objects Function Objects

    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;   }
    };
    
    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
    // of, e.g., standard library algorithms:
    if ( std::any_of(begin(v), end(v), in_interval{-2,8}) ) 
    //            custom function object ^

    Example: Interval Query Example: in_interval Example

    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_;
      }
    };
    
    // 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 Intervals Find

    standard library algorithm 'find_if' visual example
    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 }
    // 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 }

    Partitioning with Intervals Partition

    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.

    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'
    // print 2nd partition:
    for_each(i, end(v), [](int x){   std::cout << x << ' '; }); // prints '6 4 8 3 5'
    auto firstOf2ndPart = *i;  // 6
    auto splitIndex = distance(begin(v),i);  // 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., 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 Objects Standard Function Objects Std.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>
    // 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};
    cout << lexicographical_compare(  begin(v1), end(v1),                                  begin(v2), end(v2), std::greater<>{});  // true
    

    Arithmetic Operations Arithmetic

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