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

bind2nd(plus<int>(), 1)

This expression uses the plus function object to add 1 to its first argument. As we did earlier in this chapter, we use a binder adapter to make this a unary function so it can applied to the sequence by a single call to transform( ).

Another test in the program compares the elements in the two vectors for equality, so it is interesting to guarantee that at least one pair of elements is equivalent; in this case element zero is chosen.

Once the two vectors is printed, T( ) tests each of the function objects that produces a numeric value, and then B( ) tests each function object that produces a Boolean result. The result is placed into a vector<bool>, and when this vector is printed, it produces a ‘1’ for a true value and a ‘0’ for a false value. Here is the output from an execution of FunctionObjects.cpp:.

x:

4 8 18 36 22 6 29 19 25 47

y:

4 14 23 9 11 32 13 15 44 30

After testBinary(x, y, r, plus<int>()):

8 22 41 45 33 38 42 34 69 77

After testBinary(x, y, r, minus<int>()):

0 -6 -5 27 11 -26 16 4 -19 17

After testBinary(x, y, r, multiplies<int>()):

16 112 414 324 242 192 377 285 1100 1410

After testBinary(x, y, r, divides<int>()):

1 0 0 4 2 0 2 1 0 1

After testBinary(x, y, r, limit<int>()):

0 8 18 0 0 6 3 4 25 17

After testUnary(x, r, negate<int>()):

-4 -8 -18 -36 -22 -6 -29 -19 -25 -47

After testBinary(x, y, br, equal_to<int>()):

1 0 0 0 0 0 0 0 0 0

After testBinary(x, y, br, not_equal_to<int>()):

0 1 1 1 1 1 1 1 1 1

After testBinary(x, y, br, greater<int>()):

0 0 0 1 1 0 1 1 0 1

After testBinary(x, y, br, less<int>()):

0 1 1 0 0 1 0 0 1 0

After testBinary(x, y, br, greater_equal<int>()):

1 0 0 1 1 0 1 1 0 1

After testBinary(x, y, br, less_equal<int>()):

1 1 1 0 0 1 0 0 1 0

After testBinary(x, y, br, not2(greater_equal<int>())):

0 1 1 0 0 1 0 0 1 0

After testBinary(x,y,br,not2(less_equal<int>())):

0 0 0 1 1 0 1 1 0 1

b1:

0 1 1 0 0 0 1 0 1 1

b2:

0 1 1 0 0 0 1 0 1 1

After testBinary(b1, b2, br, logical_and<int>()):

0 1 1 0 0 0 1 0 1 1

After testBinary(b1, b2, br, logical_or<int>()):

0 1 1 0 0 0 1 0 1 1

After testUnary(b1, br, logical_not<int>()):

1 0 0 1 1 1 0 1 0 0

After testUnary(b1, br, not1(logical_not<int>())):

0 1 1 0 0 0 1 0 1 1

A binder doesn’t have to produce a unary predicate; it can also create any unary function (that is, a function that returns something other than bool). For example, suppose you’d like to multiply every element in a vector by 10. Using a binder with the transform( ) algorithm does the trick:.

//: C06:FBinder.cpp

// Binders aren't limited to producing predicates

#include <algorithm>

#include <functional>

#include <iostream>

#include <iterator>

#include <vector>

#include "Generators.h"

using namespace std;

int main() {

  ostream_iterator<int> out(cout," ");

  vector<int> v(15);

  generate(v.begin(), v.end(), URandGen(20));

  copy(v.begin(), v.end(), out);

  transform(v.begin(), v.end(), v.begin(),

            bind2nd(multiplies<int>(), 10));

  copy(v.begin(), v.end(), out);

} ///:~

Since the third argument to transform( ) is the same as the first, the resulting elements are copied back into the source vector. The function object created by bind2nd( ) in this case produces an int result.

The "bound" argument to a binder cannot be a function object, but it does not have to be a compile-time constant. For example:.

//: C06:BinderValue.cpp

// The bound argument can vary

#include <algorithm>

#include <functional>

#include <iostream>

#include <iterator>

using namespace std;

int boundedRand() { return rand() % 100; }

int main() {

  const int sz = 20;

  int a[sz], b[sz] = {0};

  generate(a, a + sz, boundedRand);

  int val = boundedRand();

  int* end = remove_copy_if(a, a + sz, b,

             bind2nd(greater<int>(), val));

  // Sort for easier viewing:

  sort(a, a + sz);

  sort(b, end);

  ostream_iterator<int> out(cout, " ");

  cout << "Original Sequence:\n";

  copy(a, a + sz, out); cout << endl;

  cout << "Values less <= " << val << endl;

  copy(b, end, out); cout << endl;

} ///:~

Here, an array is filled with 20 random numbers between 0 and 100, and the user provides a value on the command line. In the remove_copy_if( ) call, you can see that the bound argument to bind2nd( ) is random number in the same range as the sequence. The output of a sample execution follows.

Original Sequence:

4 12 15 17 19 21 26 30 47 48 56 58 60 63 71 79 82 90 92 95

Values less <= 41

4 12 15 17 19 21 26 30

Function pointer adapters

Wherever a function-like entity is expected by an algorithm, you can supply either a pointer to an ordinary function or a function object. When the algorithm issues a call, if it is through a function pointer, than the native function-call mechanism is used. If it through a function object, then that objects operator( ) member executes. You saw earlier, for example, that we passed a raw function, gt15( ), as a predicate to remove_copy_if( ) in the program CopyInts2.cpp. We also passed pointers to functions returning random numbers to generate( ) and generate_n( ).

You cannot, however, use raw functions with function object adapters, such as bind2nd( ), because they assume the existence of type definitions for the argument and result types. Instead of manually converting your native functions into function objects yourself, the standard library provides a family of adapters to do the work for you. The ptr_fun( ) adapters take a pointer to a function and turn it into a function object. They are not designed for a function that takes no arguments—they must only be used with unary functions or binary functions.