|
Предопределенные объекты-функции
Предопределенные объекты-функции подразделяются на арифметические, логические и сравнительные. Каждый объект – это шаблон класса, параметризованный типами операндов. Для использования любого из них необходимо включить заголовочный файл:
#include <functional>
Например, объект-функция, поддерживающий сложение, – это шаблон класса с именем plus. Для определения экземпляра, способного складывать два целых числа, нужно написать:
plus< int > intAdd;
Для выполнения операции сложения мы применяем перегруженный оператор вызова к intAdd точно так же, как и к классу AddImage в предыдущем разделе:
int ival1 = 10, ival2 = 20;
// эквивалентно int sum = ival1 + ival2;
| int sum = intAdd( ival1, ival2 );
Реализация шаблона класса plus вызывает оператор сложения, ассоциированный с типом своего параметра – int. Этот и другие предопределенные объекты-функции применяются прежде всего в качестве аргументов обобщенных алгоритмов и обычно замещают подразумеваемую по умолчанию операцию. Например, по умолчанию алгоритм sort() располагает элементы контейнера в порядке возрастания с помощью оператора “меньше” базового типа. Для сортировки по убыванию мы передаем предопределенный шаблон класса greater, который вызывает оператор “больше”:
vector< string > svec;
// ...
| sort( svec.begin(), svec.end(), greater<string>() );
Предопределенные объекты-функции перечислены в следующих разделах и разбиты на категории: арифметические, логические и сравнительные. Применение каждого из них иллюстрируется как в качестве именованного, так и в качестве безымянного объекта, передаваемого функции. Мы пользуемся следующими определениями объектов, включая и определение простого класса (перегрузка операторов подробно рассматривается в главе 15):
class Int {
public:
Int( int ival = 0 ) : _val( ival ) {}
int operator-() { return -_val; }
int operator%(int ival) { return -_val % ival; }
bool operator<(int ival) { return -_val < ival; }
bool operator!() { return -_val == 0; }
private:
int _val;
};
vector< string > svec;
string sval1, sval2, sres;
complex cval1, cval2, cres;
int ival1, ival2, ires;
Int Ival1, Ival2, Ires;
| double dval1, dval2, dres;
Кроме того, мы определяем два шаблона функций, которым передаем различные безымянные объекты-функции:
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 ); }
Арифметические объекты-функции
Предопределенные арифметические объекты-функции поддерживают операции сложения, вычитания, умножения, деления, взятия остатка и вычисления противоположного по знаку значения. Вызываемый оператор – это экземпляр, ассоциированный с типом Type. Если тип является классом, предоставляющим перегруженную реализацию оператора, то именно эта реализация и вызывается.
· Сложение: plus<Type>
plus<string> stringAdd;
// вызывается string::operator+()
sres = stringAdd( sval1, sval2 );
| dres = BinaryFunc( plus<double>(), dval1, dval2 );
· Вычитание: minus<Type>
minus<int> intSub;
ires = intSub( ival1, ival2 );
| dres = BinaryFunc( minus<double>(), dval1, dval2 );
· Умножение: multiplies<Type>
multiplies<complex> complexMultiplies;
cres = complexMultiplies( cval1, cval2 );
| dres = BinaryFunc( multiplies<double>(), dval1, dval2 );
· Деление: divides<Type>
divides<int> intDivides;
ires = intDivides( ival1, ival2 );
| dres = BinaryFunc( divides<double>(), dval1, dval2 );
· Взятие остатка: modulus<Type>
modulus<Int> IntModulus;
Ires = IntModulus( Ival1, Ival2 );
| ires = BinaryFunc( modulus<int>(), ival1, ival2 );
· Вычисление противоположного значения: negate<Type>
negate<int> intNegate;
ires = intNegate( ires );
| Ires = UnaryFunc( negate<Int>(), Ival1 );
Сравнительные объекты-функции
Сравнительные объекты-функции поддерживают операции равенства, неравенства, больше, больше или равно, меньше, меньше или равно.
· Равенство: equal_to<Type>
equal_to<string> stringEqual;
sres = stringEqual( sval1, sval2 );
ires = count_if( svec.begin(), svec.end(),
| equal_to<string>(), sval1 );
· Неравенство: not_equal_to<Type>
not_equal_to<complex> complexNotEqual;
cres = complexNotEqual( cval1, cval2 );
ires = count_if( svec.begin(), svec.end(),
| not_equal_to<string>(), sval1 );
· Больше: greater<Type>
greater<int> intGreater;
ires = intGreater( ival1, ival2 );
ires = count_if( svec.begin(), svec.end(),
| greater<string>(), sval1 );
· Больше или равно: greater_equal<Type>
greater_equal<double> doubleGreaterEqual;
dres = doubleGreaterEqual( dval1, dval2 );
ires = count_if( svec.begin(), svec.end(),
| greater_equal <string>(), sval1 );
· Меньше: less<Type>
less<Int> IntLess;
Ires = IntLess( Ival1, Ival2 );
ires = count_if( svec.begin(), svec.end(),
| less<string>(), sval1 );
· Меньше или равно: less_equal<Type>
less_equal<int> intLessEqual;
ires = intLessEqual( ival1, ival2 );
ires = count_if( svec.begin(), svec.end(),
| less_equal<string>(), sval1 );
Логические объекты-функции
Логические объекты-функции поддерживают операции “логическое И” (возвращает true, если оба операнда равны true, – применяет оператор &&, аcсоциированный с типом Type), “логическое ИЛИ” (возвращает true, если хотя бы один из операндов равен true, – применяет оператор ||, аcсоциированный с типом Type) и “логическое НЕ” (возвращает true, если операнд равен false, – применяет оператор !, аcсоциированный с типом Type)
· Логическое И: logical_and<Type>
logical_and<int> intAnd;
ires = intLess( ival1, ival2 );
| dres = BinaryFunc( logical_and<double>(), dval1, dval2 );
· Логическое ИЛИ: logical_or<Type>
logical_or<int> intSub;
ires = intSub( ival1, ival2 );
| dres = BinaryFunc( logical_or<double>(), dval1, dval2 );
· Логическое НЕ: logical_not<Type>
logical_not<Int> IntNot;
ires = IntNot( Ival1, Ival2 );
| dres = UnaryFunc( logical_or<double>(), dval1 );
Адаптеры функций для объектов-функций
В стандартной библиотеке имеется также ряд адаптеров функций, предназначенных для специализации и расширения как унарных, так и бинарных объектов-функций. Адаптеры – это специальные классы, разбитые на следующие две категории:
· связыватели (binders). Это адаптеры, преобразующие бинарный объект-функцию в унарный объект, связывая один из аргументов с конкретным значением. Например, для подсчета в контейнере всех элементов, которые меньше или равны 10, следует передать алгоритму count_if() объект-функцию less_equal, один из аргументов которого равен 10. В следующем разделе мы покажем, как это сделать;
· отрицатели (negators). Это адаптеры, изменяющие значение истинности объекта-функции на противоположное. Например, для подсчета всех элементов внутри контейнера, которые больше 10, мы могли бы передать алгоритму count_if() отрицатель объекта-функции less_equal, один из аргументов которого равен 10. Конечно, в данном случае проще передать связыватель объекта-функции greater, ограничив один из аргументов со значением 10.
В стандартную библиотеку входит два предопределенных адаптера-связывателя: bind1st и bind2nd, причем bind1st связывает некоторое значение с первым аргументом бинарного объекта-функции, а bind2nd – со вторым. Например, для подсчета внутри контейнера всех элементов, которые меньше или равны 10, мы могли бы передать алгоритму count_if() следующее:
count_if( vec.begin(), vec.end(),
| bind2nd( less_equal<int>(), 10 ));
В стандартной библиотеке также есть два предопределенных адаптера-отрицателя: not1 и not2. not1 инвертирует значение истинности унарного предиката, являющегося объектом-функцией, а not2 – значение бинарного предиката. Для отрицания рассмотренного выше связывателя объекта-функции less_equal можно написать следующее:
count_if( vec.begin(), vec.end(),
| not1( bind2nd( less_equal<int>(), 10 )));
Другие примеры использования связывателей и отрицателей приведены в Приложении, вместе с примерами использования каждого алгоритма.
Не нашли, что искали? Воспользуйтесь поиском по сайту:
©2015 - 2024 stydopedia.ru Все материалы защищены законодательством РФ.
|