Читаем Thinking In C++. Volume 2: Practical Programming полностью

template

  typename BinaryFunc>

void testBinary(Contain1& src1, Contain1& src2,

  Contain2& dest, BinaryFunc f) {

  transform(src1.begin(), src1.end(),

    src2.begin(), dest.begin(), f);

}

// Executes the expression, then stringizes the

// expression into the print statement:

#define T(EXPR) EXPR; print(r.begin(), r.end(), \

  "After " #EXPR);

// For Boolean tests:

#define B(EXPR) EXPR; print(br.begin(), br.end(), \

  "After " #EXPR);

// Boolean random generator:

struct BRand {

  BRand() { srand(time(0)); }

  bool operator()() {

    return rand() > RAND_MAX / 2;

  }

};

int main() {

  const int sz = 10;

  const int max = 50;

  vector x(sz), y(sz), r(sz);

  // An integer random number generator:

  URandGen urg(max);

  generate_n(x.begin(), sz, urg);

  generate_n(y.begin(), sz, urg);

  // Add one to each to guarantee nonzero divide:

  transform(y.begin(), y.end(), y.begin(),

    bind2nd(plus(), 1));

  // Guarantee one pair of elements is ==:

  x[0] = y[0];

  print(x.begin(), x.end(), "x");

  print(y.begin(), y.end(), "y");

  // Operate on each element pair of x & y,

  // putting the result into r:

  T(testBinary(x, y, r, plus()));

  T(testBinary(x, y, r, minus()));

  T(testBinary(x, y, r, multiplies()));

  T(testBinary(x, y, r, divides()));

  T(testBinary(x, y, r, modulus()));

  T(testUnary(x, r, negate()));

  vector br(sz); // For Boolean results

  B(testBinary(x, y, br, equal_to()));

  B(testBinary(x, y, br, not_equal_to()));

  B(testBinary(x, y, br, greater()));

  B(testBinary(x, y, br, less()));

  B(testBinary(x, y, br, greater_equal()));

  B(testBinary(x, y, br, less_equal()));

  B(testBinary(x, y, br,

    not2(greater_equal())));

  B(testBinary(x,y,br,not2(less_equal())));

  vector b1(sz), b2(sz);

  generate_n(b1.begin(), sz, BRand());

  generate_n(b2.begin(), sz, BRand());

  print(b1.begin(), b1.end(), "b1");

  print(b2.begin(), b2.end(), "b2");

  B(testBinary(b1, b2, br, logical_and()));

  B(testBinary(b1, b2, br, logical_or()));

  B(testUnary(b1, br, logical_not()));

  B(testUnary(b1, br, not1(logical_not())));

} ///:~

To keep this example short, we used a few handy tricks. The print( ) template is designed to print any sequence, along with an optional message. Since print( ) uses the copy( ) algorithm to send objects to cout via an ostream_iterator, the ostream_iterator must know the type of object it is printing, which we infer from the value_type member of the iterator passed.[83] As you can see in main( ), however, the compiler can deduce the type of T when you hand it a vector, so you don’t have to specify that template argument explicitly; you just say print(x) to print the vector x.

The next two template functions automate the process of testing the various function object templates. There are two since the function objects are either unary or binary. The testUnary( ) function takes a source vector, a destination vector, and a unary function object to apply to the source vector to produce the destination vector. In testBinary( ), two source vectors are fed to a binary function to produce the destination vector. In both cases, the template functions simply turn around and call the transform( ) algorithm, which applies the unary function/function object found in its fourth parameter to each sequence element, writing the result to the sequence indicated by its third parameter, which in this case is the same as the input sequence.

For each test, you want to see a string describing the test, followed by the results of the test. To automate this, the preprocessor comes in handy; the T( ) and B( ) macros each take the expression you want to execute. After evaluating the expression, they pass the appropriate range to print( ). To produce the message the expression is "string-ized" using the preprocessor. That way you see the code of the expression that is executed followed by the result vector.

The last little tool, BRand, is a generator object that creates random bool values. To do this, it gets a random number from rand( ) and tests to see if it’s greater than (RAND_MAX+1)/2. If the random numbers are evenly distributed, this should happen half the time.

In main( ), three vectors of int are created: x and y for source values, and r for results. To initialize x and y with random values no greater than 50, a generator of type URandGen from Generators.h is used. The standard generate_n( ) algorithm populates the sequence specified in its first argument by invoking its third argument (which must be a generator) a given number of times (specified in its second argument). Since there is one operation in which elements of x are divided by elements of y, we must ensure that there are no zero values of y. This is accomplished by once again using the transform( ) algorithm, taking the source values from y and putting the results back into y. The function object for this is created with the expression:.

bind2nd(plus(), 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, 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()):

8 22 41 45 33 38 42 34 69 77

After testBinary(x, y, r, minus()):

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

After testBinary(x, y, r, multiplies()):

16 112 414 324 242 192 377 285 1100 1410

After testBinary(x, y, r, divides()):

1 0 0 4 2 0 2 1 0 1

After testBinary(x, y, r, limit()):

0 8 18 0 0 6 3 4 25 17

After testUnary(x, r, negate()):

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

After testBinary(x, y, br, equal_to()):

1 0 0 0 0 0 0 0 0 0

After testBinary(x, y, br, not_equal_to()):

0 1 1 1 1 1 1 1 1 1

After testBinary(x, y, br, greater()):

0 0 0 1 1 0 1 1 0 1

After testBinary(x, y, br, less()):

0 1 1 0 0 1 0 0 1 0

After testBinary(x, y, br, greater_equal()):

1 0 0 1 1 0 1 1 0 1

After testBinary(x, y, br, less_equal()):

1 1 1 0 0 1 0 0 1 0

After testBinary(x, y, br, not2(greater_equal())):

0 1 1 0 0 1 0 0 1 0

After testBinary(x,y,br,not2(less_equal())):

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()):

0 1 1 0 0 0 1 0 1 1

After testBinary(b1, b2, br, logical_or()):

0 1 1 0 0 0 1 0 1 1

After testUnary(b1, br, logical_not()):

1 0 0 1 1 1 0 1 0 0

After testUnary(b1, br, not1(logical_not())):

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

#include

#include

#include

#include

#include "Generators.h"

using namespace std;

int main() {

  ostream_iterator out(cout," ");

  vector v(15);

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

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

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

            bind2nd(multiplies(), 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

#include

#include

#include

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(), val));

  // Sort for easier viewing:

  sort(a, a + sz);

  sort(b, end);

  ostream_iterator 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

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных