Chapter 21 - Notes

Function Objects

Function objects are simply objects that work as functions.

At the implementation level, function objects are objects of a class that implement operator().

struct GreetFunction {
    void operator() {
        std::cout << "Hello!" << std::endl;
    }
}

Regular functions and function pointers can also be used as function objects.

Although objects of a class implementing operator() has the added benefit of being able to contain 'state' in its member attributes. This has several useful properties when used with STL algorithms.

  • Unary function - a function called with one argument.

  • Binary function - a function called with two arguments.

Functions whose return types are bool are also referred to as predicates; these are useful for "decision making" algorithms such as std::find (does this element match my predicate?) and std::sort(should I switch these elements?).

Parameter Type

  • The auto keyword is useful for creating function pointers.

  • The actual type of a function is <return_type>(*<variable_name>)(<parameter_type>, <parameter_type>, ...)

  • The declaration void(*hello_function)() defines a function variable:

    • called hello_function

    • returns a void type

    • and takes no parameters

Unary Functions

Unary functions are functions invoked with one parameter.

Such function objects are useful for STL algorithms such as std::for_each.

Example

Create a ListPrinter unary function object that prints a particular element to the screen as a numbered list, incrementing the list each time it is invoked.

int main() {
    auto print = ListPrint();
    std::vector<std::string> names {"Alice", "Bob", "Charlie"};
    
    for_each(names.begin(),  // Start of range
             names.end(),  // End of range
             print);  // Unary function object 
}

Which should output:

1. Alice
2. Bob
3. Charlie 

Unary Predicate

Unary predicates are unary functions whose return types are bool.

Such function objects are useful for STL algorithms such as std::find_if, std::remove_if, std::partition, etcetera.

Example

Create a IsDivisibleBy unary function predicate object - this will be a struct with a constructor accepting an integer value, and an operator() implementation accepting a single argument, and returning true if the argument is perfectly divisible by the value passed to the constructor.

int main() {
    auto isDivisble = IsDivisibleBy(5);
    
    int numberToCheck;
    std::cin >> numberToCheck;
    if (isDivisible(numberToCheck)) {
        std::cout << numberToCheck << " is divisible by 5" << std::endl;
    } else {
        std::cout << numberToCheck << " is not divisible by 5" << std::endl;
    }
}

Use the function predicate object with the std::find_if algorithm.

Binary Functions

Binary functions are functions invoked with two parameters.

Such functions can be used for various arithmetic activity, such as addition, multiplication, subtraction, etcetera. For example with use with the std::transform algorithm to perform a pairwise operation between two containers.

Example

template <typename T>
struct Multiply {
    T operator() (const T& first, const T& second) {
        return first * second;
    }
}
int main() {
    std::vector<int> vectorInt1 = {1, 2, 3, 4, 5};
    std::vector<int> vectorInt2 = {10, 20, 30, 40, 50};
    
    std::vector<int> result;
    result.resize(vectorInt2.size());
    
    std::transform(vectorInt1.begin(),  // Source start range 
                   vectorInt1.end(),  // Source end range
                   vectorInt2.begin(),  // Target start range
                   result.begin(),  // Result start range
                   Multiply<int>())  // Binary function to be applied pairwise 
   
    for (auto num: result) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
}

Multiply::operator() is invoked for every pairwise element in the two vectors, the result of the operation is stored in the result vector.

Binary Predicate

Binary predicates are binary functions whose return types are bool.

Such functions are useful for STL algorithms such as std::sort.

Example

Create a binary predicate class that performs a comparison of two strings, returning true if the first string argument is alphabetically less than the second string.

Extend this predicate to perform a case-insensitive sort, by first reducing both strings to lowercase then performing the same comparison.

Use this binary predicate with the std::sort algorithm to sort a dynamic array of strings of varying case.

Last updated

Was this helpful?