Выбрать главу

//: C06:CopyInts4.cpp

// Uses a standard function object and adapter

#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 accomplishes the same thing as CopyInts3.cpp, but without our having to write our own predicate function gt15( ). The function object adapter 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. For convenience, let’s also call the instance of the output stream iterator by the name o. Then the call to remove_copy_if( ) earlier 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( ) adapter 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 adapter, not1( ), that take 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 of course 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 in this case 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))