The standard library defines a set of classes that represent the arithmetic, relational, and logical operators. Each class defines a call operator that applies the named operation. For example, the plus
class has a function-call operator that applies +
to a pair of operands; the modulus
class defines a call operator that applies the binary %
operator; the equal_to
class applies ==;
and so on.
These classes are templates to which we supply a single type. That type specifies the parameter type for the call operator. For example, plus<string>
applies the string
addition operator to string
objects; for plus<int>
the operands are int
s; plus<Sales_data>
applies +
to Sales_data
s; and so on:
plus<int> intAdd; // function object that can add two int values
negate<int> intNegate; // function object that can negate an int value
// uses intAdd::operator(int, int) to add 10 and 20
int sum = intAdd(10, 20); // equivalent to sum = 30
sum = intNegate(intAdd(10, 20)); // equivalent to sum = -30
// uses intNegate::operator(int) to generate -10 as the second parameter
// to intAdd::operator(int, int)
sum = intAdd(10, intNegate(10)); // sum = 0
These types, listed in Table 14.2, are defined in the functional
header.
The function-object classes that represent operators are often used to override the default operator used by an algorithm. As we’ve seen, by default, the sorting algorithms use operator<
, which ordinarily sorts the sequence into ascending order. To sort into descending order, we can pass an object of type greater
. That class generates a call operator that invokes the greater-than operator of the underlying element type. For example, if svec
is a vector<string>
,
// passes a temporary function object that applies the < operator to two strings
sort(svec.begin(), svec.end(), greater<string>());
sorts the vector
in descending order. The third argument is an unnamed object of type greater<string>
. When sort
compares elements, rather than applying the <
operator for the element type, it will call the given greater
function object. That object applies >
to the string
elements.
One important aspect of these library function objects is that the library guarantees that they will work for pointers. Recall that comparing two unrelated pointers is undefined (§ 3.5.3, p. 120). However, we might want to sort
a vector
of pointers based on their addresses in memory. Although it would be undefined for us to do so directly, we can do so through one of the library function objects:
vector<string *> nameTable; // vector of pointers
// error: the pointers in nameTable are unrelated, so < is undefined
sort(nameTable.begin(), nameTable.end(),
[](string *a, string *b) { return a < b; });
// ok: library guarantees that less on pointer types is well defined
sort(nameTable.begin(), nameTable.end(), less<string*>());
It is also worth noting that the associative containers use less<key_type>
to order their elements. As a result, we can define a set
of pointers or use a pointer as the key in a map
without specifying less
directly.
Exercise 14.42: Using library function objects and adaptors, define an expression to
(a) Count the number of values that are greater than 1024
(b) Find the first string that is not equal to pooh
(c) Multiply all values by 2
Exercise 14.43: Using library function objects, determine whether a given int
value is divisible by any element in a container of int
s.