predefined function objects c++
The C++ standard
library contains several predefined function objects that cover fundamental operations. By
using them, you don't have to write your own function objects in several cases.
A typical example is a function object used as a sorting criterion. The default
sorting criterion for operator < is the predefined sorting criterion less<>.
Thus, if you declare
set<int>
coll;
it is expanded
to
set<int,
less<int> > coll; //sort elements with <
From there, it
is easy to sort elements in the opposite order:
Note that you
have to put a space between the two ">" characters. ">>"
would be parsed as shift operator, which would result in a syntax error.
set<int
,greater<int> > coll; //sort elements with >
Similarly, many
function objects are provided to specify numeric processing. For example, the following
statement negates all elements of a collection:
transform
(coll.begin() , coll.end(), //source
coll.begin(), //destination
negate<int>())
; //operation
The expression creates
a function object of the predefined template class negate that simply returns
the negate element of type int for which it is called. The transform() algorithm
uses that operation to transform all elements of the first collection into the
second collection. If source and destination are equal (as in this case), the
returned negated elements overwrite themselves. Thus, the statement negates
each element in the collection.
Similarly, you
can process the square of all elements in a collection:
//process the
square of all elements
transform
(coll.begin(), coll.end(), //first source
coll.begin(), //second
source
coll.begin(), //destination
multiplies<int>())
; //operation
Here, another
form of the transform() algorithm combines elements of two collections by using
the specified operation, and writes the resulting elements into the third
collection. Again, all collections are the same, so each element gets
multiplied by itself, and the result overwrites the old value.
Note: In earlier
versions of the STL, the function object for multiplication had the name times.
This was changed due to a name clash with a function of operating system standards
(X/Open, POSIX) and because multiplies was clearer.
By using special
function adapters you can combine predefined function objects with other
values or use special cases. Here is a complete example:
With the
statement
transform
(coll1.begin() ,coll1.end() //source
back_inserter
(coll2) , //destination
bind2nd(multiplies<int>()
,10)) ; //operation
all elements of coll1
are transformed into coll2 (inserting) while multiplying each element by
10. Here, the
function adapter bind2nd causes multiply<int> to be called for each
element of the source collection as the first argument and the value 10 as the
second.
The way bind2nd operates
is as follows: transform() is expecting as its fourth argument an operation
that takes one argument; namely, the actual element. However, we would like to multiply
that argument by ten. So, we have to combine an operation that takes two
arguments and the value that always should be used as a second argument to get
an operation for one argument. bind2nd does that job. It stores the operation
and the second argument as internal values. When the algorithm calls bind2nd with
the actual element as the argument, bind2nd calls its operation with the
element from the algorithm as the first argument and the internal value as the
second argument, and returns the result of the operation.
Similarly, in
replace_if
(coll2.begin(),coll2.end(), //range
bind2nd(equal_to<int>(),70),
//replace criterion
42);
the expression
bind2nd(equal_to<int>(),70)
is used as a
criterion to specify the elements that are replaced by 42. bind2nd calls the
binary
predicate equal_to
with value 70 as the second argument, thus defining a unary predicate for
the elements of
the processed collection. The last statement is similar because the expression
bind2nd(less<int>(),50)
elements that
are less than value 50 be removed. The output of the program is as follows:
initialized: 9 8
7 6 5 4 3 2 1
transformed: 90
80 70 60 50 40 30 20 10
replaced: 90 80
42 60 50 40 30 20 10
removed: 90 80
60 50
This kind of
programming results in functional composition. What is interesting is
that all these function objects are usually declared inline. Thus, you use a
function-like notation or abstraction, but you get good performance.
There are other
kinds of function objects. For example, some function objects provide the ability
to call a member function for each element of a collection:
for_each
(coll.begin(), coll.end(), //range
mem_fun_ref
(&Person: : save)); //operation
The function
object mem_fun_ref calls a specified member function for the element for which
it is called. Thus, for each element of the collection coll, the member
function save() of class Person is called. Of course, this works only if the
elements have type Person or a type derived from Person.
No comments:
Post a Comment