Чтение онлайн

на главную - закладки

Жанры

Эффективное использование STL
Шрифт:

Впрочем,

not1
— не единственный компонент STL, предъявляющий подобные требования. Все четыре стандартных адаптера (
not1
,
not2
,
bind1st
и
bind2nd
), а также все нестандартные STL-совместимые адаптеры из внешних источников (например, входящие в SGI и Boost — см. совет 50), требуют существования некоторых определений типов. Объекты функций, предоставляющие необходимые определения типов, называются адаптируемыми; при отсутствии этих определений объект называется неадаптируемым. Адаптируемые объекты функций могут использоваться в контекстах, в которых невозможно
использование неадаптируемых объектов, поэтому вы должны по возможности делать свои объекты функций адаптируемыми. Адаптируемость не требует никаких затрат, но значительно упрощает использование классов функторов клиентами.

Наверное, вместо туманного выражения «некоторые определения типов» вы бы предпочли иметь точный список? Речь идет об определениях

argument_type
,
first_argument_type
,
second_argument_type
и
result_type
, но ситуация осложняется тем, что разные классы функторов должны предоставлять разные подмножества этих имен. Честно говоря, если вы не занимаетесь разработкой собственных адаптеров, вам вообще ничего не нужно знать об этих определениях. Как правило, определения наследуются от базового класса, а говоря точнее — от базовой структуры. Для классов функторов, у которых
operator
вызывается с одним аргументом, в качестве предка выбирается структура
std::unary_function
. Классы функторов, у которых
operator
вызывается с двумя аргументами, наследуют от структуры
std::binary_function
.

Впрочем, не совсем так.

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

Пара примеров:

template<typename T>

class MeetsThreshold: public std::unary_function<Widget, bool> {

private:

 const T threshold;

public:

 Meets Threshold(const T& threshold);

 bool operator(const WidgetS) const;

 …

};

struct WidgetNameCompare:

 std::binary_function<Widget, Widget, bool> {

 bool operator(const Widget& lhs, const Widget& rhs) const;

};

В обоих случаях типы, передаваемые

unary_function
или
binary_function
, совпадают с типами, получаемыми и возвращаемыми функцией
operator
класса функтора, хотя на первый взгляд несколько странно, что тип возвращаемого значения
operator
передается в последнем аргументе
unary_function
или
binary_function
.

Возможно, вы заметили, что

MeetsTheshold
является классом, а
WidgetNameCompare
является структурой.
MeetsTheshold
обладает внутренним состоянием (переменная
threshold
), и для инкапсуляции этих данных логично воспользоваться именно классом.
WidgetNameCompare
состояния не имеет, поэтому и закрытые данные
не нужны. Авторы классов функторов, в которых вся информация является открытой, часто объявляют структуры вместо классов — вероятно, только для того, чтобы им не приходилось вводить «
public
» перед базовым классом и функцией
operator
. Выбор между классом и структурой при объявлении таких функторов определяется исключительно стилем программирования. Если вы еще не выработали собственного стиля и стараетесь имитировать профессионалов, учтите, что классы функторов без состояния в самой библиотеке STL (например,
less<T>
,
plus<T>
и т. д.) обычно записываются в виде структур.

Вернемся к определению WidgetNameCompare:

struct WidgetNameCompare:

 std::binary_function<Widget, Widget, bool> {

 bool operator(const Widget& lhs, const Widget& rhs) const;

};

Хотя аргументы

operator
относятся к типу const
Widget&
, шаблону
binary_function
передается тип
Widget
. Обычно при передаче
unary_function
или
binary_function
типов, не являющихся указателями, ключевые слова
const
и знаки ссылки удаляются… только не спрашивайте, почему, — ответ на этот вопрос не интересен и не принципиален. Если вы сгораете от любопытства, напишите программу, в которой они не удаляются, и проанализируйте полученную диагностику компилятора. А если вы и после этого не утратите интерес к этой теме, посетите сайт boost.org (см. совет 50) и поищите на нем информацию об адаптерах объектов функций.

Если

operator
получает параметры-указатели, ситуация меняется. Ниже приведена структура, аналогичная
WidgetNameCompare
, но работающая с указателями
Widget*
:

struct PtrWidgetNameCompare:

 std::binary_function<const Widget*, const Widget*, bool> {

 bool operator(const Widget* lhs, const Widget* rhs) const;

};

В этом случае типы, передаваемые

binary_function
, совпадают с типами, передаваемыми
operator
. Общее правило для классов функторов, получающих или возвращающих указатели, заключается в том, что
unary_function
или
binary_function
передаются в точности те типы, которые получает или возвращает
operator
.

Помните, что базовые классы

unary_function
и
binary_function
выполняют только одну важную функцию — они предоставляют определения типов, необходимые для работы адаптеров, поэтому наследование от этих классов порождает адаптируемые объекты функций. Это позволяет использовать в программах следующие конструкции:

list<Widget> widgets;

list<Widget>::reverse_iterator i1 = // Найти последний объект

 find_if(widgets.rbegin, widgets.rend, // Widget, не соответствующий

 not1(MeetsThreshold<int>(10))); // пороговому критерию 10

//(что бы это ни означало)

Widget w(аргументы конструктора); // Найти первый объект Widget.

list<Widget>::iterator i2 = // предшествующий w в порядке

 find_if(widgets.begin, widgets.end, // сортировки, определенном

Поделиться:
Популярные книги

Как я строил магическую империю 4

Зубов Константин
4. Как я строил магическую империю
Фантастика:
боевая фантастика
постапокалипсис
аниме
фантастика: прочее
фэнтези
5.00
рейтинг книги
Как я строил магическую империю 4

Безумный Макс. Поручик Империи

Ланцов Михаил Алексеевич
1. Безумный Макс
Фантастика:
героическая фантастика
альтернативная история
7.64
рейтинг книги
Безумный Макс. Поручик Империи

Попаданка 3

Ахминеева Нина
3. Двойная звезда
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Попаданка 3

Муж на сдачу

Зика Натаэль
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Муж на сдачу

Призыватель нулевого ранга. Том 3

Дубов Дмитрий
3. Эпоха Гардара
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Призыватель нулевого ранга. Том 3

На границе империй. Том 10. Часть 5

INDIGO
23. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 10. Часть 5

Адвокат

Константинов Андрей Дмитриевич
1. Бандитский Петербург
Детективы:
боевики
8.00
рейтинг книги
Адвокат

На границе империй. Том 7

INDIGO
7. Фортуна дама переменчивая
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
6.75
рейтинг книги
На границе империй. Том 7

Здравствуй, 1985-й

Иванов Дмитрий
2. Девяностые
Фантастика:
альтернативная история
5.25
рейтинг книги
Здравствуй, 1985-й

О, Путник!

Арбеков Александр Анатольевич
1. Квинтет. Миры
Фантастика:
социально-философская фантастика
5.00
рейтинг книги
О, Путник!

Чужбина

Седой Василий
2. Дворянская кровь
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Чужбина

Бестужев. Служба Государевой Безопасности. Книга четвертая

Измайлов Сергей
4. Граф Бестужев
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бестужев. Служба Государевой Безопасности. Книга четвертая

Локки 5. Потомок бога

Решетов Евгений Валерьевич
5. Локки
Фантастика:
юмористическое фэнтези
аниме
фэнтези
5.00
рейтинг книги
Локки 5. Потомок бога

На границе империй. Том 10. Часть 4

INDIGO
Вселенная EVE Online
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 10. Часть 4