В программе PLUSAIR
показали, как применять функциональный объект plus<>()
с алгоритмом accumulate()
. В том примере не было необходимости в передаче каких-либо аргументов в функциональный объект, но иногда по логике работы программы это требуется. Оказывается, в данном случае нельзя просто указать аргумент в скобках, как мы привыкли делать. Вместо этого нужно использовать специальный «адаптер функции», называющийся bind1st
или bind2nd
, для связывания аргумента с функциональным объектом. Пусть, например, мы ищем строку SearchName
в строковом контейнере names
. В этом случае необходимо писать такое выражение:
ptr = find_if(names.begin(), names.end(), bind2nd(equal_to<string>(), SearchName));
Обычно в этом учебнике в каждой главе сначала дается теория, иллюстрируемая примерами в виде небольших программ, потом — два-три десятка вопросов по теории и 12 упражнений. Некоторые кусочки теории автор иногда выносит в задания к упражнениям. Здесь именно такой случай. То есть в теоретической части главы о функциональных адаптерах
bind1st
и bind2nd
не рассказывалось.Почему эти функции называются адаптерами? «Адаптер» — это по-русски «переходник», по крайней мере, в данном случае. Функциональный адаптер на входе получает функцию с двумя параметрами, а на выходе выдает функцию с одним параметром, вот и получается функциональный переходник. В приведенном выше примере с алгоритмом
find_if
в третьем параметре к нему должна быть задана функция с одним параметром (унарный предикат), а у нас имеется функция (функциональный объект) с двумя параметрами equal_to<>()
, поэтому и используется переходник bind2nd
.Что означают названия
bind1st
и bind2nd
? Слово «bind» в переводе с английского на русский означает «привязывать». Слово «1st» — это сокращение от «first» («первый»), а слово «2nd» — сокращение от «second» («второй»). То есть функциональный адаптер bind1st
связывает заданное значение с первым параметром заданной функции, а bind2nd
связывает заданное значение со вторым параметром заданной функции.Источник:
https://en.cppreference.com/w/cpp/utility/functional/bind12
Самое интересное, что в указанном выше коде можно безболезненно заменить
bind2nd
на bind1st
. Почему так происходит? Эти адаптеры взаимозаменяемы в случае симметричных операций, то есть таких бинарных операций, в которых перемена мест операндов не приводит к изменению результата. Симметричные операции — это сложение (при перемене мест слагаемых сумма не меняется), умножение и так далее. В нашем случае — проверка на равенство (equal_to<>()
) — тоже симметричная операция.Мне понравился пример, приведенный на сайте Stackoverflow.com, поясняющий разницу между
bind1st
и bind2nd
:int main () { auto p1 = bind1st(plus<int>(),10); auto p2 = bind2nd(plus<int>(),10); cout << p1(20) << endl; // 10 + 20 = 30 cout << p2(20) << endl; // 20 + 10 = 30 auto m1 = bind1st(minus<int>(),10); auto m2 = bind2nd(minus<int>(),10); cout << m1(20) << endl; // 10 – 20 = –10 cout << m2(20) << endl; // 20 – 10 = 10 return 0; }
Тут, во-первых, хорошо видна работа функциональных адаптеров как переходников от функций с двумя параметрами к функциям с одним параметром. А во-вторых, видно, чем отличаются
bind1st
и bind2nd
и как они выдают одинаковый результат в случае сложения параметров (симметричная операция) и разный результат в случае вычитания параметров (несимметричная операция).Источник:
https://stackoverflow.com/questions/6863677/use-bind1st-or-bind2nd
В заключение надо бы отметить, что применение данных функциональных адаптеров не одобряется стандартом C++11, а стандартом C++17 эти функциональные адаптеры вообще удалены из языка C++. Как я понимаю, вместо них предлагается использовать функциональный адаптер
std::bind
:https://en.cppreference.com/w/cpp/utility/functional/bind
Например, вместо
ptr = find_if(names.begin(), names.end(), bind2nd(equal_to<string>(), SearchName));Можно написать так:
using namespace std::placeholders; ptr = find_if(names.begin(), names.end(), bind(equal_to<string>(), _1, SearchName));
В моей среде разработки «Visual Studio Community 2017» и операционной системе «Windows 7» прекрасно работают оба эти варианта.
Кстати, решение 9-го упражнения к 15-й главе учебника Лафоре можно посмотреть тут.