Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com
Answertopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions
Privacy Policy

  




 

 

Thinking in C++ Vol 2 - Practical Programming
Prev Home Next

Automatic creation of function objects

The <functional> header defines a number of useful generic function objects. They are admittedly simple, but you can use them to compose more complicated function objects. Consequently, in many instances, you can construct complicated predicates without writing a single function. You do so by using function object adaptors[90] to take the simple function objects and adapt them for use with other function objects in a chain of operations.

To illustrate, let s use only standard function objects to accomplish what gt15( ) did earlier. The standard function object, greater, is a binary function object that returns true if its first argument is greater than its second argument. We cannot apply this directly to a sequence of integers through an algorithm such as remove_copy_if( ) because remove_copy_if( ) expects a unary predicate. We can construct a unary predicate on the fly that uses greater to compare its first argument to a fixed value. We fix the value of the second parameter at 15 using the function object adaptor bind2nd, like this:

//: C06:CopyInts4.cpp
// Uses a standard function object and adaptor.
#include <algorithm>
#include <cstddef>
#include <functional>
#include <iostream>
#include <iterator>
using namespace std;
 
int main() {
int a[] = { 10, 20, 30 };
const size_t SIZE = sizeof a / sizeof a[0];
remove_copy_if(a, a + SIZE,
ostream_iterator<int>(cout, "\n"),
bind2nd(greater<int>(), 15));
} ///:~
 

This program produces the same result as CopyInts3.cpp, but without writing our own predicate function gt15( ). The function object adaptor bind2nd( ) is a template function that creates a function object of type binder2nd, which simply stores the two arguments passed to bind2nd( ), the first of which must be a binary function or function object (that is, anything that can be called with two arguments). The operator( ) function in binder2nd, which is itself a unary function, calls the binary function it stored, passing it its incoming parameter and the fixed value it stored.

To make the explanation concrete for this example, let s call the instance of binder2nd created by bind2nd( ) by the name b. When b is created, it receives two parameters (greater<int>( ) and 15) and stores them. Let s call the instance of greater<int> by the name g, and call the instance of the output stream iterator by the name o. Then the call to remove_copy_if( ) earlier conceptually becomes the following:

remove_copy_if(a, a + SIZE, o, b(g, 15).operator());
 

As remove_copy_if( ) iterates through the sequence, it calls b on each element, to determine whether to ignore the element when copying to the destination. If we denote the current element by the name e, that call inside remove_copy_if( ) is equivalent to

if(b(e))
 

but binder2nd s function call operator just turns around and calls g(e,15), so the earlier call is the same as

if(greater<int>(e, 15))
 

which is the comparison we were seeking. There is also a bind1st( ) adaptor that creates a binder1st object, which fixes the first argument of the associated input binary function.

As another example, let s count the number of elements in the sequence not equal to 20. This time we ll use the algorithm count_if( ), introduced earlier. There is a standard binary function object, equal_to, and also a function object adaptor, not1( ), that takes a unary function object as a parameter and invert its truth value. The following program will do the job:

//: C06:CountNotEqual.cpp
// Count elements not equal to 20.
#include <algorithm>
#include <cstddef>
#include <functional>
#include <iostream>
using namespace std;
 
int main() {
int a[] = { 10, 20, 30 };
const size_t SIZE = sizeof a / sizeof a[0];
cout << count_if(a, a + SIZE,
not1(bind1st(equal_to<int>(), 20)));// 2
} ///:~
 

As remove_copy_if( ) did in the previous example, count_if( ) calls the predicate in its third argument (let s call it n) for each element of its sequence and increments its internal counter each time true is returned. If, as before, we call the current element of the sequence by the name e, the statement

if(n(e))
 

in the implementation of count_if is interpreted as

if(!bind1st(equal_to<int>, 20)(e))
 

which ends up as

if(!equal_to<int>(20, e))
 

because not1( ) returns the logical negation of the result of calling its unary function argument. The first argument to equal_to is 20 because we used bind1st( ) instead of bind2nd( ). Since testing for equality is symmetric in its arguments, we could have used either bind1st( ) or bind2nd( ) in this example.

The following table shows the templates that generate the standard function objects, along with the kinds of expressions to which they apply:

Name

Type

Result produced

plus

BinaryFunction

arg1 + arg2

minus

BinaryFunction

arg1 - arg2

multiplies

BinaryFunction

arg1 * arg2

divides

BinaryFunction

arg1 / arg2

modulus

BinaryFunction

arg1 % arg2

negate

UnaryFunction

- arg1

equal_to

BinaryPredicate

arg1 == arg2

not_equal_to

BinaryPredicate

arg1 != arg2

greater

BinaryPredicate

arg1 > arg2

less

BinaryPredicate

arg1 < arg2

greater_equal

BinaryPredicate

arg1 >= arg2

less_equal

BinaryPredicate

arg1 <= arg2

logical_and

BinaryPredicate

arg1 && arg2

Logical_or

BinaryPredicate

arg1 || arg2

logical_not

UnaryPredicate

!arg1

unary_negate

Unary Logical

!(UnaryPredicate(arg1))

binary_negate

Binary Logical

!(BinaryPredicate(arg1, arg2))

 

Thinking in C++ Vol 2 - Practical Programming
Prev Home Next

 
 
   Reproduced courtesy of Bruce Eckel, MindView, Inc. Design by Interspire