Таким образом, вызов вызываемого объекта g() вызывает вызываемый объект f() с использованием аргументов вызываемого объекта g() для знакомест наряду с аргументами a, b и с. Например, вызов g(X, Y) приводит к вызову f(a, b, Y, с, X).

Использование функции bind() для переупорядочивания параметров

Рассмотрим более конкретный пример применения функции bind() для переупорядочивания аргументов. Используем ее для обращения смысла функции isShorter() следующим образом:

// сортировка по длине слов от коротких к длинным

sort(words.begin(), words.end(), isShorter);

// сортировка по длине слов от длинных к коротким

sort(words.begin(), words.end(), bind(isShorter, _2, _1));

В первом вызове, когда алгоритм sort() должен сравнить два элемента, А и В, он вызовет функцию isShorter(A, В). Во втором вызове аргументы функции isShorter() меняются местами. В данном случае, когда алгоритм sort() сравнивает элементы, он вызывает функцию isShorter(В, А).

Привязка ссылочных параметров

По умолчанию аргументы функции bind(), не являющиеся знакоместами, копируются в возвращаемый ею вызываемый объект. Однако, подобно лямбда-выражениям, иногда необходимо связать аргументы, которые следует передать по ссылке, или необходимо связать аргумент, тип которого не допускает копирования.

Для примера заменим лямбда-выражение, которое захватывало поток ostream по ссылке:

// os - локальная переменная, ссылающаяся на поток вывода

// с - локальная переменная типа char

for_each(words.begin(), words.end(),

         [&os, c] (const string &s) { os << s << c; });

Вполне можно написать функцию, выполняющую ту же задачу:

ostream &print(ostream &os, const string &s, char c) {

 return os << s << c;

}

Но для замены захвата переменной os нельзя использовать функцию bind() непосредственно:

// ошибка: нельзя копировать os

for_each(words.begin(), words.end(), bind(print, os, _1, ' '));

Поскольку функция bind() копирует свои аргументы, она не сможет скопировать поток ostream. Если объект необходимо передать функции bind(), не копируя, то следует использовать библиотечную функцию ref():

for_each(words.begin(), words.end(),

         bind(print, ref(os), _1, ' '));

Функция ref() возвращает объект, который содержит переданную ссылку, являясь при этом вполне копируемым. Существует также функция cref(), создающая класс, содержащий ссылку на константу. Подобно функции bind(), функции ref() и cref() определены в заголовке functional.

Совместимость с прежней версией: привязка аргументов

Прежние версии языка С++ имели много больше ограничений, и все же более сложный набор средств привязки аргументов к функциям. Библиотека определяет две функции — bind1st() и bind2nd(). Подобно функции bind(), эти функции получают функцию и создают новый вызываемый объект для вызова переданной функции с одним из ее параметров, связанным с переданным значением. Но эти функции могут связать только первый или второй параметр соответственно. Поскольку они имеют очень много ограничений, в новом стандарте эти функции не рекомендованы. Это устаревшее средство, которое может не поддерживаться в будущих выпусках. Современные программы С++ должны использовать функцию bind().

Упражнения раздела 10.3.4

Упражнение 10.22. Перепишите программу подсчета слов размером 6 символов с использованием функций вместо лямбда-выражений.

Упражнение 10.23. Сколько аргументов получает функции bind()?

Упражнение 10.24. Используйте функции bind() и check_size() для поиска первого элемента вектора целых чисел, значение которого больше длины заданного строкового значения.

Перейти на страницу:

Похожие книги