Like any other class, a function-object class can have additional members aside from operator()
. Function-object classes often contain data members that are used to customize the operations in the call operator.
As an example, we’ll define a class that prints a string
argument. By default, our class will write to cout
and will print a space following each string
. We’ll also let users of our class provide a different stream on which to write and provide a different separator. We can define this class as follows:
class PrintString {
public:
PrintString(ostream &o = cout, char c = ' '):
os(o), sep(c) { }
void operator()(const string &s) const { os << s << sep; }
private:
ostream &os; // stream on which to write
char sep; // character to print after each output
};
Our class has a constructor that takes a reference to an output stream and a character to use as the separator. It uses cout
and a space as default arguments (§ 6.5.1, p. 236) for these parameters. The body of the function-call operator uses these members when it prints the given string
.
When we define PrintString
objects, we can use the defaults or supply our own values for the separator or output stream:
PrintString printer; // uses the defaults; prints to cout
printer(s); // prints s followed by a space on cout
PrintString errors(cerr, '
'),
errors(s); // prints s followed by a newline on cerr
Function objects are most often used as arguments to the generic algorithms. For example, we can use the library for_each
algorithm (§ 10.3.2, p. 391) and our PrintString
class to print the contents of a container:
for_each(vs.begin(), vs.end(), PrintString(cerr, ' '));
The third argument to for_each
is a temporary object of type PrintString
that we initialize from cerr
and a newline character. The call to for_each
will print each element in vs
to cerr
followed by a newline.
Exercise 14.33: How many operands may an overloaded function-call operator take?
Exercise 14.34: Define a function-object class to perform an if-then-else operation: The call operator for this class should take three parameters. It should test its first parameter and if that test succeeds, it should return its second parameter; otherwise, it should return its third parameter.
Exercise 14.35: Write a class like PrintString
that reads a line of input from an istream
and returns a string
representing what was read. If the read fails, return the empty string
.
Exercise 14.36: Use the class from the previous exercise to read the standard input, storing each line as an element in a vector
.
Exercise 14.37: Write a class that tests whether two values are equal. Use that object and the library algorithms to write a program to replace all instances of a given value in a sequence.