1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
|
Many tt(STL) algorithms require us to specify predicates. For example
tt(count_if()) (ref(COUNT)), tt(find_if()) (ref(FIND)), tt(min_element())
(ref(MINEL)) or tt(search()) (ref(SEARCH)). In these cases a function
object must be provided whose tt(operator()()) member is called, defining the
predicate function. Conditional to its argument(s), it returns tt(true) or
tt(false).
Sometimes a simple emi(predicate function) already exists. For example tt(int
isdigit(int)) returns if its argument is a character representing a digit,
otherwise 0; tt(char *strchr(char const *, int)) returns a non-0 pointer if
the set of characters provided as its first argument contains the character
represented by its second argument, and returns 0 otherwise.
Existing unary predicate functions may be specified with the
tt(PredicateFunction1) class template, defining a unary predicate class. Its
ti(argument_type) using-declaration is required by, e.g., function adapters:
verbinclude(//UNARYPRED examples/predicates.h)
Existing binary predicate functions may be specified with the
tt(PredicateFunction2) class template, defining a binary predicate class. Its
ti(first_argument_type), ti(second_argument_type) and
ti(result_type) using-declarations are required by, e.g., function adapters:
verbinclude(//BINPRED examples/predicates.h)
Here is an example of their use, counting the number of digits appearing
at the program's standard input stream:
verbinclude(-a examples/predfun.cc)
Alternatively, although the function operator is called when a predicate
function is used, the actual member function we have available might
be another function or a useful member may be available from an object of
another class. In that case an object acting as em(man in the middle) might
come in handy. The following class tt(PredicateObject1) performs exactly that
function. It defines a class template whose parameters refer to a class and a
data type. Its constructors expect a pointer or reference to an object of the
template parameter's class as well as a pointer to a member function of that
class implementing a predicate. By default it's the class's function object
operator. Here is its definition:
verbinclude(//PREDOBJ1 examples/predicates.h)
The class tt(PredicateObject2) can be used to construct a
emi(binary predicate) object. Here the class template has three
parameters: the class type of the object passed to its constructor as well as
the types of the two arguments of the binary predicate member that's called:
verbinclude(//PREDOBJ2 examples/predicates.h)
The object passed to these constructors is not copied by generic
algorithms, in contrast to the tt(PredicateObject)s themselves, which em(are)
copied. The object specified when instantiating the tt(PredicateObject)s must
actually exist before the instantiation takes place. Also, the object's
members do not have to be tt(const) member functions, thus allowing
modifications of the passed object's data. Function adapters may be
used with the tt(PredicateObject)s as well.
Here is an example using tt(PredicateObject)s. The program counts the
number of words containing vowels appearing at the program's standard input
stream. First a support class tt(Contains) is defined. It's a simple class
defining unary and binary predicate functions:
verbinclude(//CONTAINS examples/predobj.cc)
When the program is called without arguments its unary predicate object
functionality is used, otherwise its binary predicate object
functionality. Here is the program's tt(main()) function:
verbinclude(//MAIN examples/predobj.cc)
|