Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
STL5 / lab8-functors / lab8-STL-functor.doc
Скачиваний:
9
Добавлен:
10.04.2015
Размер:
259.07 Кб
Скачать

Отрицатели

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

Отрицатели при конструировании получают одинарный или двоичный предикат, а при вызове возвращают значение, соответствующее отрицанию результата вычисления переданного при конструировании функтора. Так если при конструировании отрицателю был передан предикат predicate, то результатом вызова отрицателя будет !predicate(x) (для двоичного предиката !predicate(x,y).

Отрицатели имеют следующее определение:

// Отрицатель для функтора с одним аргументом

template<class Pred>

class unary_negate: public unary_function<Pred::argument_type, bool>

{

public:

explicit unary_negate(const Pred& x);

bool operator()(const Pred::argument_type& _X) const;

};

// Отрицатель для функтора с двумя аргументами

template<class BinPred>

class binary_negate:

public binary_function<BinPred::first_argument_type,

BinPred::second_argument_type,

bool>

{

public:

explicit binary_negate(const BinPred& x);

bool operator()(const BinPred::first_argument_type& x,

const BinPred::second_argument_type& x) const;

};

Рассмотрим более детально определение unary_negate. Видно, что это функтор, который принимает один аргумент, тип которого совпадает с типом аргумента отрицаемого функтора и возвращает значение типаbool. Отметим, что тип аргумента отрицаемого функтора определяется на основе имени типаargument_type, которое должно быть определено в отрицаемом функторе. Теперь становится понятно, почему все совместимые сSTLфункторы должны наследовать отunary_functionилиbinary_function, в этих базовых классах определены используемыеSTLимена типов1. Из определения также видно, что конструктор отрицателя принимает в качестве параметра ссылку на функтор-предикат, этот предикат будет использован для вычисления значение, которое будет изменено отрицателем на противоположное (trueнаfalse, аfalseнаtrue). Оператор вызова функции принимает в качестве аргумента тип, соответствующий типу аргумента отрицаемого функтора. Аналогичные замечания можно сделать, посмотрев на определение функтораbinary_negate.

Ниже приведена возможная реализация этих функторов, она не обязательно должна быть такой, но тем не менее приведенный код поясняет принцип работы отрицателя.

template<class Pred>

class unary_negate: public unary_function<Pred::argument_type, bool>

{

public:

explicit unary_negate(const Pred& x) : pr(x) {}

bool operator()(const Pred::argument_type& x) const

{

return !pr(x);

}

protected:

Pred pr;

};

template<class BinPred>

class binary_negate:

public binary_function<BinPred::first_argument_type,

BinPred::second_argument_type,

bool>

{

public:

explicit binary_negate(const BinPred& x) : bin_pr(x) {}

bool operator()(const BinPred::first_argument_type& x,

const BinPred::second_argument_type& y) const

{

return !bin_pr(x,y);

}

protected:

BinPred bin_pr;

};

Кроме непосредственно самих отрицателей в STLприсутствую две функцииnot1 иnot2, которые на основе переданного им предиката с одним или двумя аргументами создают отрицатель для этого предиката. Ниже приведены их определения:

template<class Pred>

inline unary_negate<Pred> not1(const Pred& x)

{

return (unary_negate<Pred>(x));

};

template<class BinPred>

inline binary_negate<BinPred> not2(const BinPred& x)

{

return (binary_negate<BinPred>(x));

}

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

vector<int> vec;

. . . // заполнить вектор

// найти первое значение, не удовлетворяющее предикату

find_if(vec.begin(),vec.end(),not1(predicate));

вместо

vector<int> vec;

. . . // заполнить вектор

// найти первое значение, не удовлетворяющее предикату

find_if(vec.begin(),vec.end(),unary_negate<predicate>()));

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

#include <vector>

#include <iostream>

#include <algorithm>

#include <functional>

#include <cstdlib>

using namespace std;

void print (int arg)

{

cout << arg << ',';

};

class IsEven : public unary_function<int,bool>

{

public:

bool operator() (int arg) const

{

return (arg % 2) == 0;

}

};

int main (int, char**)

{

vector<int> v;

int i;

for (i = 0; i < 15; i++)

v.push_back(i);

for_each(v.begin(),v.end(),print);

cout << endl;

v.erase(remove_if(v.begin(),v.end(),not1(IsEven())),v.end());

for_each(v.begin(),v.end(),print);

cout << endl;

return 0;

}

Вывод программы:

0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,

0,2,4,6,8,10,12,14,

Соседние файлы в папке lab8-functors