Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 128
Текст из файла (страница 128)
Также нет функции логически достаточной, чтобы выразить все, что мы хотим. Зачастую функция, вызываемая для каждого элемента, нуждается э сохранении данных между вызовами и в возвращении результата многих обращений, Функция-член класса служит таким нуждам лучше, чем обычная функция, поскольку сохранять данные может объект соответствующего класса. Кроме того, класс в состоянии обеспечить операции для инициализации и извлечения таких данных. Давайте рассмотрим, как написать функцию — или, точнее, функции-подобный класс — для вычисления суммы: Глава 18.
Алгоритмы и объекты-функции 578 переданную по указателю. Поэтому объекты-функции зачастую выполняются быстрее, чем обычные функции. Объект какого-либо класса с оператором () Я 11.9) пазывается обьектом-функцией, функтором, обьектом типа функция или функциональным обьектом.
18.4.1. Базовые классы для объектов-Функций Стандартная библиотека предоставляет множество полезных обьектов-функций. Для помощи в написании объектов-функций библиотека предусматривает несколько базовых классов: 1етр!а1е<с!авв Агу, с!авв Рев> в1гис! ипату йкпсиол ( 1урет(е) Агу агуитепг 1уре; 1урейеГРев гезий 1уре; 1етр!а1е<с!акк Ага с1авв Агу2, с!акк Рев> к!гик! Ь!лагу !йлс1!оп ( !уреаеТАгуу!гв1 агуител! 1уре; турес!е(Агу2 ее<оп<( аоуител1 1уре; 1урес!е) Рев гевиИ 1уре; Назначение этих классов — дать стандартные имена типам аргументам и возвращаемых значеннй для использования в классах, производных от ипагу ~ипс1!оп и Ькпагу /ипс1!оп. Используя эти базовые классы должным образом (так, как это делает стандартная библиотека), программист избавится от долгих мучений, которые все равно рано нли поздно приведут к осознанию необходимости правильного применения базовых классов Я 18А.4.1).
18.4.2. Предикаты Предикат — это объект-функция (или просто функция), возвращающая значение типа Ьоо!. Например, заголовочный файл <!ипс)!опа(> содержит такие определения: 1етр1асе<с1авв Т ктгис1 !оу!са! по1 риЬЙс ипагу ~иле!!оп<Т, Ьоо1> ( Ьоо! орега1ог () (сопк! Т& х) соле! ( ге1игп ~х; ) 1етр!а1е<с!ивк Т кмис! !екк, риЬЙсЬ!лагу Гипс!!оп<Т, Т, Ьоо1>( Ьоо! орега1ог)) (сопв! Т& х, сопв1 Т& у) сопв1( ге1игп х<у; ) Унарные и бинарные цредикаты часто бывают полезны в сочетании с алгоритмами. Например, мы можем сравнить две последовательности в поисках элемента первой последовательности, который был бы не меньше соответствующего элемента во второй последовательности: оопЦ(иес1е~ .тР & гу Йв1<!п1> & Й) ( 1урег(ст Йвс<!пехтега1огЕ1; !урсс!е) оес1ог !л1>. !1ега1ог И, ра!г<Ъ'1, ТЛ> р! = т!ктатсЬ (ш'.Ьеу!л (), !!Ьеу!и (), !евк<!пР ()); б...
18.4. Объекты-функции 579 Ллгоритл~ т!вта1сН (( !несоответствие) многократно применяет свой бинарный преликат к парам соответствующих элементов до первой неудачи Я 18.5А). Затем он возвращает итераторы для элементов, не удовлетворивших условию. Поскольку нужен объект, а петин, используется 1евв<т1> (] !со скобками), а не соблазнительное 1евв<!п~ .
Вместо поиска первого элемента не лленьшего, чем соответствующий элемент в другой последовательности, мы могли бы захотеть найти первгяй элемент, меньший чем соответствующий элемент в другой последовательности. Мы но>кем сделать зто, отыскивая первую пару, которая не удовлетворяет дополнительному предикату йгеа1ег ег!иа1 (больп>е или равно): р! = т(кта1сН (еНЬед(п ((, гйелН (Л Н.ЬеН)п З, ягеагег едиа!<гпг> (1(, или представив алгоритму т!втагсй () последовательности в обратном порядке и использовав !екв еуиа1: ра(г<!2, 1>7> р2 = >пытагсЬ (Н>6ей1п ((, Непй ((, э!6еНН> ((, !екк едиа1<1пФ ((); В 9 18ААА я покажу, как выразить преднкат «не меньше».
18.4.2.1. Обзор предикатов В заголовочном файле <~иле!!опа1> стандартная библиотека предоставляет несколь- ко постоянно используемых предикатов: Предикаты <йпсс(опа1> Определения 1евк и 1оп!са! ло1 даны в 9 18.4.2. Кроме библиотечных предикатов пользователь может написать собственные. Пользовательские предикаты необходимы для простого н изящного использования стандартных библиотек контейнеров и алгоритмов.
В частности, возможность определять предикаты важна, когда нужно воспользоваться алгоритмами для классов, разработанных не на основе стандартной библиотеки и ее алгоритмов. Наприл>ер, рассмотрим вариант класса С1иЬ из 5 10.4.б: с1иккРегкоп ( /' ... '> Ь кггисг С1и6 ( кгг1лд пате; Нк1<регкоп'> тетьегк; Нк1<регкоп*> оЦ1сегк; 0- С(и6 (солт кгппдй и); ); !1'член»~ клдба 11 персонал ег!иа! 1о ло! едиа! 1о дгеа1ег !екк а еа1ег едиа! 1евк ег!иа! 1ой>са! алг! 1ойтса! ог 1оятса! по! Бинарный Бинарный Бинарный Бинарный Бинарный Бинарный Бинарный Бинарный Увари ый ага! == агн2 агу!! = ага2 ага! > агд2 ага! < ага2 ага! >= агН2 агу! <= агд2 ага! 7»8 ага агй! (( агн2 !агд' Глава 18. Алгоритмы и обьекты-функции 580 Поиск объекта типа С1иЬ с данным именем пате в списке 1ы!< С1иб> — явно осмысленная вещь (это поиск клуба с данным названием).
Однако стандартный алгоритмфис( (г () ничего не знает о типе С1иЬ. Библиотечные алгоритмы умеют проверять на равенство, но нам пе нужно искать объект типа С1иб по его полному значению. Мы хотим использовать в качестве кл!оча поиска С1абспате, И чтобы это отразить, мы напишем предикат: с!пкк С!иЬ ед; риЬ!!с ипагу Гипс!!оп<С!иб, Ьоо!> ( Иг!пя к; риЫ!с: ехр1!с!! С!иЬ ед (сопк! к!ппдй кк): к (кк) () Ьоо! ар его !ог () ( сопк! С!обй с) со пк1 ( ге1игп с. а иге===; ) Определить полезные предикаты не трудно. А как только они введены для типов, определяемых пользователем, применение этих типов со стандартными алгоритма- ми становится так же просто и эффективно, как и в примере с контейнерами простых типов. Например: оо!с!1' (1!к!<С!иб>й 1с) !уредеГ !!к!<С!иб>сйега1ог ЕС1, ЕС1р =Япс! буг(!с.беутп (), !с.епс! (), С!иЬ ед ('Филососбы за обедом")).
,1,!.- ) 18.4.3. Арифметические объекты-функции Когда имеешь дело с числовыми классами, иногда полезно иметь стандартные арифметические функции, доступные как объекты-функции. Поэтому в заголовоч- ном файле <1апс!1ола1> стандартная библиотека предоставляет арифметические операции: Арифметические операции <1цпс1(опа(> Мы могли бы при помощи ти1!!р1!ез перемножить элементы двух векторов, тем са- мым получив третий: сои! д!ксоиаг (иес!ог с!оиб(е>8 а, пес!ос<доиЫе>$ В, пес!ос<с!оиб!е>8 ге4 ( !гиак1огт (а.Ьеят (), и.епс! (), Ь.бед!п (), Ьасб пакет!ег(геф, ти!краек<доиЫе> ()); Функция Ьасб тзег!ег () описана в 9 19.2.4.
Несколько численных алгоритмов мож- но найти в Э 22.6. р1аз т!аиз ти11!р11ез с(!о!с1ез тос(и(аз пейа1е Бинарный Бинарный Бинарный Бинарный Бинарный Увари ый аги1 + аги2 ага1 — ага2 аго1 * аги2 ага1 / агя2 ага1 'l. ага2 — агу1 18.4. Объекты-функции 581 18.4.4. Связыватели, адаптеры и отрицатели Связыватели, адаптеры и отрицатели <гипс(1опа)> Функция Ьии(2пс( (у) Ыпс(!з! (х) тет 1ип() Тип объекта Действие объекта (орегасог () ()) Ь!пН2пс( Ь|па1з! Вызывает бинарную функцию с у в качестве второго аргумента Вызывает бинарную функцию с х в качестве первого аргумента Вызывает О-аргументную функцию-член через указатель Вызывает унарную функцию-член через указатель Вызывает О-аргументную константную функцию-член через указатель Вызывает унарную константную функцию-член через указатель Вызывает О-аргументную функцию-член через ссылку Вызывает унарную функцию-член через ссылку Вызывает О-аргументную константную функцию-член через ссылку Вызывает унарную константную функцию-член через ссылку тет ~ип ! тет1ип1 ! сопя! тет ~ип ! сопя! тет )ип1 ! тет)ип ге1'() тетгип ге1 ! тет!ип1 ге1' ! сопл! тет (ип ге1 ! сопя! тет 1ип! ге! ! Мы можем пользоваться предикатами и арифметическими функциями, которые сами написали, а также предикатами и арифметическими функциями из стандартной библиотеки, Однако когда нужен новый предикат, мы часто обнаруживаем, что он лишь незначительно отличается от уже существующего.
Стандартная библиотека поддерживает композицию объектов-функций: э 18.4.4.1 Связывагпель ()япдег) позволяет использовать объект-функцию с двумя -аргументами как функцию с одним аргументом путем связывания одного аргумента со значением. э 18.4.4.2 Адаптер функций-членов позволяет использовать функции-члены как аргументы алгоритмов. э 18.4А.З Адаптер указателя на функцию позволяет использовать указатель иа функцию как аргумент алгоритма. э 18.4.4А Отрицатель позволяет нам выразить противоположный предикат. Все вместе эти объекты-функции называют адаптерами.
Все они имеют общую структуру, опирающуюся на базовые для объектов-функций классы ипагу 1ипс!1оп и Ь(пагу гипс(1оп (э 18.4.1). Для каждого из этих адаптеров существует функция-помошник, принимающая объект-функцию в качестве аргумента и возвращающая другой объект-функцию, Вызванный его оператором, этот объект-функция выполнит желаемое действие. То есть адаптер — это простая форма функции высшего порядка: он берет функцию-аргумент и производит из нее новую функцию. Глава 18. Алгоритмы и объекты-функции 582 Связыватели, адаптеры и отрицатели <йтпс1!опа!> (продолхсеиие) Тип объекта Действие объекта (орегагог () ()) Функция р1гЯип() ро(п1ег 1о ипагу 7ипс1(оп р1г !ип () рогп1ег 1о Ыпагу !ипс1(оп Вызывает унарный указатель на функцию Вызывает бинарный указатель на функцию Заменяет унарный предикат на противоположный Заменяет бинарный предикат на противоположный по1! () ипагу пеуа1е по12 () Ыпагу пеуа1е 18.4.4.1.