|
Программирование >> Разработка устойчивых систем
В сигнатурах будут использоваться обозначения LessThanComparable, Assignable и EqualityCompa-гаЫе. - Примеу. перев. это самостоятельно - в стандартной библиотеке это уже сделано за вас. Следующее описание объектов функций не только улучщит ваще представление о них, но и поможет лучще разобраться в том, как работают обобщенные алгоритмы. Классификация объектов функций в стандартной библиотеке С++ объекты функций 1слассифицируются по количеству аргументов, передаваемых оператору () (ноль, один или два), и возвращаемому значению. Генератор - категория объектов функций, вызываемых без аргументов и возвращающих значение произвольного типа. Примером генератора может служить генератор случайных чисел. В стандартную библиотеку входит один генератор (функция rand(), объявленная в файле <cstdlib>), а также некоторые алгоритмы (например, generate n()), применяющие генераторы к элементам интервалов. Унарная функция - категория объектов функций, вызываемых с одним аргументом произвольного типа и возвращающих значение, которое может относиться к другому типу (в том числе void). Бинарная функция - категория объектов функций, вызываемых с двумя аргументами любых двух (в том числе различных) типов и возвращающих значение произвольного типа (в том числе void). Унарный предикат - унарная функция, возвращающая bool. Бинарный предикат - бинарная функция, возвращающая bool. Строгая квазиупорядоченность - бинарный предикат, обеспечивающий расширенную интерпретацию понятия равенство . Некоторые стандартные контейнеры считают два элемента равными (или эквивалентными), если ни один из них не меньше другого (по критерию <). Это существенно при сравнении вещественных чисел и объектов других типов, когда оператор ненадежен или недоступен. Понятие строгой квазиупорядоченности также применяется при сортировке структур (записей данных) по подмножеству полей структуры. Две структуры с равными ключами не равны как объекты в целом, но они считаются равными в контексте критерия сравнения. Важность концепции строгой квазиупорядоченности станет очевидна в следующей главе. Кроме того, некоторые алгоритмы подразумевают определенные предположения относительно того, какие операции поддерживаются для типов обрабатываемых объектов. Для обозначения этих предположений будут использоваться следующие термины: с поддержкой < - класс поддерживает оператор меньше <; с поддержкой присваивания - класс поддерживает оператор копирующего присваивания = для своего типа; с поддержкой = = - класс поддерживает оператор проверки равенства - для своего типа. В данной главе эти термины будут использоваться для описания обобщенных алгоритмов стандартной библиотеки. Автоматическое создание объектов функций в заголовочном файле <functional> определяется целый ряд полезных объектов функций общего назначения. Сами по себе такие объекты достаточно просты, но они могут использоваться для построения более сложных объектов функций. Нередко вместо того, чтобы самостоятельно писать сложные предикаты, программист конструирует их из готовых строительных блоков . Задача решается при помощи адаптеров объектов функций, которые получают простые объекты функций и комбинируют их с другими объектами функций в цепочке операций. Чтобы пояснить сказанное, давайте с использованием только стандартных объектов функций сделаем то, что делалось раньше функцией gtl5(). Стандартный бинарный объект функции greater возвращает true, если его первый аргумент меньше второго. Однако его не удастся напрямую применить к интервалам целых чисел при помощи алгоритма вроде remove copyJf(), поскольку алгоритм remove copyJf() должен получать унарный предикат. Проблема легко решается - мы конструируем унарный предикат, использующий greater для сравнения своего первого аргумента с фиксированной величиной. Значение второго параметра фиксируется равным 15 при помощи адаптера bind2nd, как показано ниже: : СОб:СоруInts4.срр Использование стандартного объекта функции и адаптера linclude <algorithm> linclude <cstddef> linclude <functional> linclude <iostreani> linclude <iterator> using namespace std: int mainO { int a[] = { 10. 20. 30 }: const size t SIZE = sizeof a / sizeof a[0]: remove copy if(a. a + SIZE. ost reamj terator<i nt>(cout. \n ). bind2nd(greater<int>(). 15)): } III:- Программа выводит тот же результат, что и CopyInts3,cpp, но нам не потребовалось писать собственную функцию-предикат gtl5(). Адаптер bind2nd() представляет собой шаблонную функцию, которая создает объект функции типа binder2nd. Этот объект просто сохраняет два аргумента, переданных bind2nd(); первый аргумент должен быть бинарной функцией или объектом функции (то есть чем угодно, что может вызываться с двумя аргументами). Функция operator() в binder2nd сама по себе является унарной, но она вызывает хранящуюся в ней бинарную функцию и передает ей параметр и фиксированное значение. Рассмотрим конкретный пример. Допустим, экземпляр binder2nd, созданный bind2nd(), называется Ь. При создании b получает два параметра (greater<int> и 15) и сохраняет их. Для удобства обозначим экземпляр greater<int> именем д, а экземпляр потокового итератора вывода - о. Тогда приведенный выше вызов remove copyJf() концептуально выглядит так: remove copy if(a. a+SIZE. о. b(g, 15).operatorO): В процессе перебора интервала алгоритм remove copy if() вызывает b для каждого элемента; в зависимости от результата вызова он решает, нужно ли игнорировать элемент при копировании в приемник. Если обозначить текуший элемент именем е, этот вызов внутри remove copyJf() эквивалентен следующему: 1f(b(e)) Однако оператор вызова функции binder2nd просто вызывает д(еД5), поэтому приведенная команда эквивалентна такой: if(greater<int>(e.l5)) А это и есть нужное сравнение. Также существует адаптер bindlst для создания объекта binderlst, фиксирующего первый аргумент бинарной функции. Еще один пример: подсчет количества элементов интервала, отличных от 20. На этот раз будет использоваться алгоритм count if(), упоминавшийся ранее. В библиотеке определен стандартный объект бинарной функции equal to и адаптер notl(), который получает объект унарной функции и возвращает его логическое отрицание. Следующая программа делает то, что требуется: : C06:CountNotEqua1.срр Подсчет элементов, не равных 20 linclude <algorithm> linclude <cstddef> linclude <funct1onal> linclude <iostream> using namespace std: int mainO { int a[] = { 10. 20, 30 }; const size t SIZE = sizeof a / sizeof a[0]: cout count if(a. a + SIZE. notl(bindlst(equal to<1nt>(), 20))); 2 } /:- Алгоритм count if() вызывает предикат, переданный в третьем аргументе (назовем его п), для каждого элемента своего интервала. Каждый раз, когда предикат возвращает true, алгоритм увеличивает свой внутренний счетчик. По аналогии с предыдущим примером обозначим текущий элемент символом е и рассмотрим команду if (п(е)) В реализации countjf эта команда интерпретируется так: if(!(b1ndlst(equal to<int>. 20)(е)) В конечном счете выражение принимает следующий вид, так как адаптер notl() возвращает логическое отрицание своего аргумента (результата вызова унарной функции): if(!equal to<1nt>(20. е)) Первый аргумент equal to равен 20, потому что вместо bind2nd() используется адаптер bindlst(). Проверка на равенство симметрична по отношению к своим аргументам; следовательно, в нашем примере можно было задействовать как bindlstQ, так и bind2nd(). В табл. 6.1 перечислены шаблоны, генерирующие стандартные объекты функций (с указанием контекста применения).
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |