As we’ve shown in this chapter, many Standard Library algorithms allow you to pass a lamda or a function pointer into the algorithm to help the algorithm perform its task. For example, the binary_search
algorithm that we discussed in Section 16.4.6 is overloaded with a version that requires as its fourth parameter a function that takes two arguments and returns a bool
value. The algorithm uses this function to compare the search key to an element in the collection. The function returns true
if the search key and element being compared are equal; otherwise, the function returns false
. This enables binary_search
to search a collection of elements for which the element type does not provide an overloaded <
operator.
Any algorithm that can receive a lambda or function pointer can also receive an object of a class that overloads the function-call operator (parentheses) with a function named operator()
, provided that the overloaded operator meets the requirements of the algorithm—in the case of binary_search
, it must receive two arguments and return a bool
. An object of such a class is known as a function object and can be used syntactically and semantically like a lambda, a function or a function pointer—the overloaded parentheses operator is invoked by using a function object’s name followed by parentheses containing the arguments to the function. Most algorithms can use lambdas, function pointers and function objects interchangeably.2 In fact, lambdas are converted by the compiler into function pointers or function objects, which can be inlined by the compiler for optimization purposes.
Function objects provide several advantages over function pointers. The compiler can sometimes inline a function object’s overloaded operator()
to improve performance. Also, since they’re objects of classes, function objects can have data members that operator()
can use to perform its task.
Many predefined function objects can be found in the header <functional>
. Figure 16.14 lists several of the dozens of Standard Library function objects, which are all implemented as class templates—you can see the complete list at
http://en.cppreference.com/w/cpp/utility/functional
Section 20.9 of the C++ standard contains the complete list of function objects. We used the function object less<T>
in the set
and multiset
examples to specify the sorting order for elements in a container. Recall that many of the overloaded Standard Library algorithms can receive as their last argument a binary function that determines whether its first argument is less than its second—exactly the purpose of the less<T>
function object.
Function object | Type |
---|---|
divides<T> |
arithmetic |
equal_to<T> |
relational |
greater<T> |
relational |
greater_equal<T> |
relational |
less<T> |
relational |
less_equal<T> |
relational |
logical_and<T> |
logical |
logical_not<T> |
logical |
logical_or<T> |
logical |
minus<T> |
arithmetic |
modulus<T> |
arithmetic |
negate<T> |
arithmetic |
not_equal_to<T> |
relational |
plus<T> |
arithmetic |
multiplies<T> |
arithmetic |
accumulate
AlgorithmFigure 16.15 uses the accumulate
numeric algorithm (introduced in Fig. 16.6) to calculate the sum of the squares of the elements in an array
. The fourth argument to accumulate
is a binary function object (that is, a function object for which operator()
takes two arguments) or a function pointer to a binary function (that is, a function that takes two arguments). Function accumulate
is demonstrated three times—once with a function pointer, once with a function object and once with a lamdba.
sumSquares
Lines 13–15 define a function sumSquares
that squares its second argument value
, adds that square and its first argument total
and returns the sum. Function accumulate
will pass each of the elements of the sequence over which it iterates as the second argument to sumSquares
in the example. On the first call to sumSquares
, the first argument will be the initial value of the total
(which is supplied as the third argument to accumulate
; 0
in this program). All subsequent calls to sumSquares
receive as the first argument the running sum returned by the previous call to sumSquares
. When accumulate
completes, it returns the sum of the squares of all the elements in the sequence.
SumSquaresClass
Lines 20–27 define the class template SumSquaresClass
with an overloaded operator()
that has two parameters and returns a value—the requirements for a binary function object. On the first call to the function object, the first argument will be the initial value of the total
(which is supplied as the third argument to accumulate
; 0
in this program) and the second argument will be the first element in array
integers
. All subsequent calls to operator()
receive as the first argument the result returned by the previous call to the function object, and the second argument will be the next element in the array
. When accumulate
completes, it returns the sum of the squares of all the elements in the array
.
accumulate
Lines 39–40 call function accumulate
with a pointer to function sumSquares
as its last argument. Similarly, the statement in lines 47–48 call accumulate
with an object of class SumSquaresClass
as the last argument. Finally, lines 55–56 call accumulate
with an equivalent lambda.
The expression SumSquaresClass<int>{}
in line 48 creates (and calls the default constructor for) an object of class SumSquaresClass
(a function object) that’s passed to accumulate
, which invokes the function operator()
. Lines 47–48 could be written as two separate statements, as follows:
SumSquaresClass<int> sumSquaresObject;
result = accumulate(integers.cbegin(), integers.cend(),
0, sumSquaresObject);
The first line defines an object of class SumSquaresClass
, which is then passed to accumulate
in the subsequent statement.