Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ для начинающих (Стенли Липпман) 3-е хххх.pdf
Скачиваний:
84
Добавлен:
30.05.2015
Размер:
5.92 Mб
Скачать

С++ для начинающих

560

 

template <class FuncObject, class Type>

 

 

 

 

Type UnaryFunc( FuncObject fob, const Type &val )

 

 

{ return fob( val ); }

 

 

template <class FuncObject, class Type>

 

 

Type BinaryFunc( FuncObject fob,

 

 

const Type &val1, const Type &val2 )

 

 

{ return fob( val1, val2 ); }

 

 

 

 

 

 

12.3.2. Арифметические объекты-функции

Предопределенные арифметические объекты-функции поддерживают операции сложения, вычитания, умножения, деления, взятия остатка и вычисления противоположного по знаку значения. Вызываемый оператор это экземпляр, ассоциированный с типом Type. Если тип является классом, предоставляющим перегруженную реализацию оператора, то именно эта реализация и вызывается.

plus<string> stringAdd;

// вызывается string::operator+() sres = stringAdd( sval1, sval2 );

∙ Сложение: plus<Type>

dres = BinaryFunc( plus<double>(), dval1, dval2 );

minus<int> intSub;

ires = intSub( ival1, ival2 );

∙ Вычитание: minus<Type>

dres = BinaryFunc( minus<double>(), dval1, dval2 );

multiplies<complex> complexMultiplies; cres = complexMultiplies( cval1, cval2 );

∙ Умножение: multiplies<Type>

dres = BinaryFunc( multiplies<double>(), dval1, dval2 );

divides<int> intDivides;

ires = intDivides( ival1, ival2 );

∙ Деление: divides<Type>

dres = BinaryFunc( divides<double>(), dval1, dval2 );

Взятие остатка: modulus<Type>

С++ для начинающих

561

modulus<Int> IntModulus;

Ires = IntModulus( Ival1, Ival2 );

ires = BinaryFunc( modulus<int>(), ival1, ival2 );

negate<int> intNegate; ires = intNegate( ires );

∙ Вычисление противоположного значения: negate<Type>

Ires = UnaryFunc( negate<Int>(), Ival1 );

12.3.3. Сравнительные объекты-функции

Сравнительные объекты-функции поддерживают операции равенства, неравенства, больше, больше или равно, меньше, меньше или равно.

equal_to<string> stringEqual;

sres = stringEqual( sval1, sval2 );

ires = count_if( svec.begin(), svec.end(),

Равенство: equal_to<Type>

equal_to<string>(), sval1 );

not_equal_to<complex> complexNotEqual; cres = complexNotEqual( cval1, cval2 ); ires = count_if( svec.begin(), svec.end(),

Неравенство: not_equal_to<Type>

not_equal_to<string>(), sval1 );

greater<int> intGreater;

ires = intGreater( ival1, ival2 );

ires = count_if( svec.begin(), svec.end(),

Больше: greater<Type>

greater<string>(), sval1 );

greater_equal<double> doubleGreaterEqual; dres = doubleGreaterEqual( dval1, dval2 ); ires = count_if( svec.begin(), svec.end(),

Больше или равно: greater_equal<Type>

С++ для начинающих

562

greater_equal <string>(), sval1 );

less<Int> IntLess;

Ires = IntLess( Ival1, Ival2 );

ires = count_if( svec.begin(), svec.end(),

Меньше: less<Type>

less<string>(), sval1 );

less_equal<int> intLessEqual;

ires = intLessEqual( ival1, ival2 );

ires = count_if( svec.begin(), svec.end(),

Меньше или равно: less_equal<Type>

less_equal<string>(), sval1 );

12.3.4. Логические объекты-функции

Логические объекты-функции поддерживают операции логическое И” (возвращает true, если оба операнда равны true, – применяет оператор &&, аcсоциированный с типом Type), “логическое ИЛИ” (возвращает true, если хотя бы один из операндов равен true, – применяет оператор ||, аcсоциированный с типом Type) и логическое НЕ” (возвращает true, если операнд равен false, – применяет оператор !, аcсоциированный с типом Type)

logical_and<int> intAnd;

ires = intLess( ival1, ival2 );

Логическое И: logical_and<Type>

dres = BinaryFunc( logical_and<double>(), dval1, dval2 );

logical_or<int> intSub;

ires = intSub( ival1, ival2 );

Логическое ИЛИ: logical_or<Type>

dres = BinaryFunc( logical_or<double>(), dval1, dval2 );

logical_not<Int> IntNot;

ires = IntNot( Ival1, Ival2 );

Логическое НЕ: logical_not<Type>

dres = UnaryFunc( logical_or<double>(), dval1 );

С++ для начинающих

563

12.3.5. Адаптеры функций для объектов-функций

В стандартной библиотеке имеется также ряд адаптеров функций, предназначенных для специализации и расширения как унарных, так и бинарных объектов-функций. Адаптеры это специальные классы, разбитые на следующие две категории:

связыватели (binders). Это адаптеры, преобразующие бинарный объект-функцию в унарный объект, связывая один из аргументов с конкретным значением. Например, для подсчета в контейнере всех элементов, которые меньше или равны 10, следует передать алгоритму count_if() объект-функцию less_equal, один из аргументов которого равен 10. В следующем разделе мы покажем, как это сделать;

отрицатели (negators). Это адаптеры, изменяющие значение истинности объекта- функции на противоположное. Например, для подсчета всех элементов внутри контейнера, которые больше 10, мы могли бы передать алгоритму count_if() отрицатель объекта-функции less_equal, один из аргументов которого равен 10. Конечно, в данном случае проще передать связыватель объекта-функции greater, ограничив один из аргументов со значением 10.

В стандартную библиотеку входит два предопределенных адаптера-связывателя: bind1st и bind2nd, причем bind1st связывает некоторое значение с первым аргументом бинарного объекта-функции, а bind2nd со вторым. Например, для подсчета внутри контейнера всех элементов, которые меньше или равны 10, мы могли бы передать

count_if( vec.begin(), vec.end(),

алгоритму count_if() следующее:

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

В стандартной библиотеке также есть два предопределенных адаптера-отрицателя: not1 и not2. not1 инвертирует значение истинности унарного предиката, являющегося объектом-функцией, а not2 значение бинарного предиката. Для отрицания рассмотренного выше связывателя объекта-функции less_equal можно написать

count_if( vec.begin(), vec.end(),

следующее:

not1( bind2nd( less_equal<int>(), 10 )));

Другие примеры использования связывателей и отрицателей приведены в Приложении, вместе с примерами использования каждого алгоритма.

12.3.6. Реализация объекта-функции

При реализации программы в разделе 12.2 нам уже приходилось определять ряд объектов-функций. В этом разделе мы изучим необходимые шаги и возможные вариации при определении класса объекта-функции. (В главе 13 определение класса рассматривается детально; в главе 15 обсуждается перегрузка операторов.)

С++ для начинающих

564

В самой простой форме определение класса объекта-функции сводится к перегрузке оператора вызова. Вот, например, унарный объект-функция, определяющий, что

// простейшая форма класса объекта-функции class less_equal_ten {

public:

bool operator() ( int val ) { return val <= 10; }

некоторое значение меньше или равно 10:

};

Теперь такой объект-функцию можно использовать точно так же, как предопределенный. Вызов алгоритма count_if() с помощью нашего объекта-функции выглядит следующим образом:

count_if( vec.begin(), vec.end(), less_equal_ten() );

Разумеется, возможности этого класса весьма ограничены. Попробуем применить

count_if( vec.begin(), vec.end(),

отрицатель, чтобы подсчитать, сколько в контейнере элементов, больших 10: not1(less_equal_then ()));

или обобщить реализацию, разрешив пользователю задавать значение, с которым надо сравнивать каждый элемент контейнера. Для этого достаточно ввести в класс член для хранения такого значения и реализовать конструктор, инициализирующий данный член

class less_equal_value { public:

less_equal_value( int val ) : _val( val ) {}

bool operator() ( int val ) { return val <= _val; }

private: int _val;

указанной пользователем величиной:

};

Новый объект-функция применяется для задания произвольного целого значения. Например, при следующем вызове подсчитывается число элементов, меньших или равных 25:

count_if( vec.begin(), vec.end(), less_equal_value( 25 ));

Разрешается реализовать класс и без конструктора, если параметризовать его значением, с которым производится сравнение: