====== В двух словах ======
Boost Lambda Library (далее BLL) - библиотека шаблонов C++, которая имплементирует форму lambda-абстракций (//lambda abstractions//) для C++. Термин происходит из функционального программирования и lambda-вычислений, где lambda-абстракция определяет безымянную функцию (//unnamed function//). Первичная мотивировка для BLL – обеспечить гибкий, и удобный способ определения безымянных функциональных объектов для алгоритмов STL. В объяснении, чем является библиотека, строка кода говорит больше чем тысяча слов; следующая строка выводит разделенные пробелами элементы некоторого контейнера:
for_each (a.begin (), a.end (), std::cout<<_1<<'');
Выражение std:: cout <<_1 <<' ' определяет одиночный функциональный объект. Переменная _1 –параметр этой функции, метка-заполнитель (//placeholder//) для фактического параметра. В пределах каждой итерации for_each, функция вызывается с элементом **a** в качестве фактического параметра. Этот фактический параметр подставляется вместо //placeholder//, и определяется "тело" функции. Сущность BLL позволяет Вам определять маленькие безымянные функциональные объекты, такие как предыдущий, непосредственно в месте вызова алгоритма STL.
====== Введение ======
===== Обоснование =====
Стандартная Библиотека Шаблонов (STL) [ [[ http://www.boost.org/doc/html/lambda.html#cit:stepanov:94 | STL94]]], теперь часть Стандартной Библиотеки C++ [ [[http://www.boost.org/doc/html/lambda.html#cit:c++:98 | C++98]]], является основной библиотекой контейнеров и алгоритмов. Обычно алгоритмы STL выполняют операции над элементами контейнера через функторы. Эти функторы передаются алгоритмам в качестве аргументов. Любая конструкция C++, которая может быть вызвана с синтаксисом вызова функции, - функтор. STL содержит предопределенные функторы для некоторых общих операторов (типа 'плюс','меньше' и 'not 1'). Как пример, возможное имплементирование для шаблона стандартного плюса:
template
struct plus : public binary_function{
T operator()(const T& i, const T& j) const { return i + j; }
};
Базовый класс binary_function содержит typedefs для параметров и возвращаемых типов функтора, которые необходимы, чтобы сделать функциональный объект адаптируемым. В дополнение к основным функторам классов, таких как указаны выше, STL содержит шаблоны связывания (//binder templates//) для создания унарного функтора из адаптируемого бинарного функтора, фиксированием одного из параметров константным значением. Например, вместо имеющегося, явно написать функтор как:
class plus_1 {
int _i;
public:
plus_1(const int& i) : _i(i) {}
int operator()(const int& j) { return _i + j; }
};
эквивалентная функциональность может быть достигнута с шаблоном plus и одним из шаблонов связывания(//bind1st//). Например, следующие два выражения создают функторы с идентичными функциональными возможностями; когда вызваются, оба возвращают результат добавления 1 к аргументу функтора:
plus_1(1)
bind1st(plus(), 1)
Подвыражение plus() в последней строке - бинарный функтор, который вычисляет сумму двух целых чисел, и bind1st вызывает этот функтор, частично привязав первый аргумент к 1. В качестве примера использования вышеупомянутого функтора, следующий код добавляет 1 к каждому элементу некоторого контейнера **a** и выводит результаты в поток стандартного вывода cout.
transform(a.begin(),a.end(),ostream_iterator(cout),bind1st(plus(),1));
Чтобы сделать шаблоны связывания более широко применимыми, STL содержит адаптеры для выполнения указателей или ссылок на функции и указателей на функции-члены, адаптируемыми. Наконец, некоторые реализации STL содержат функциональные составные операции, как расширения Стандарта [ [[http://www.boost.org/doc/html/lambda.html#cit:sgi:02 | SGI02]]].
Все эти средства стремятся к одной цели: позволить определить безымянные функции в вызове алгоритма STL, другими словами, передавать фрагменты кода в качестве параметра функции. Однако, эта цель достигнута только частично. Простой пример выше показывает, что определение безымянных функций стандартными средствами является громоздким. Сложные выражения, задействующие функторы, адаптеры, биндеры(//binders//) и функциональные составные операции трудны для понимания. В дополнение к этому, есть существенные ограничения в применении стандартных средств. Например, стандартные биндеры позволяют связать только один аргумент бинарной функции; нет никаких биндеров для 3-х, 4-х и т.д. функций.
Boost Lambda Library обеспечивает решения, описанных выше проблем:
* Безымянные функции могут быть созданы легко и с интуитивно-понятным синтаксисом. Вышеупомянутый пример может быть записан как:
transform(a.begin(), a.end(), ostream_iterator(cout), 1 + _1);
или ещё более понятно:
for_each(a.begin(), a.end(), cout << (1 + _1));
* Удалено большинство ограничений для аргументов связывания, могут быть связаны произвольные параметры фактически любой функции C++ .
* Нет необходимости в разделении функциональных составных операций, поскольку функциональная композиция поддерживается неявно.
===== Введение в lambda-выражения =====
Lambda-выражения обычны для функциональных языков программирования. Их синтаксис варьируется между языками (и между различными формами lambda-исчислений), но каноническая форма lambda-выражений такова:
lambda x1...xn.e
Lambda-выражение определяет безымянную функцию и состоит из:
* параметров этой функции: x1...xn.
* выражения e, которое вычисляет значение функции в границах x1...xn.
Простой пример lambda-выражения:
lambda x y.x+y
Применение lambda-функции означает замену формальных параметров фактическими:
(lambda x y.x+y) 2 3 = 2 + 3 = 5
В версии lambda-выражений для C++ часть lambda x1...xn, и формальные параметры имеют предопределенные названия. В текущей версии библиотеки, есть три таких предопределенных формальных параметра, названные метками-заполнителями: _1, _2 и _3. Они обращаются к первому, второму и третьему параметру функции, определенной lambda-выражением. Например, в C++ версия определения
lambda x y.x+y
это
_1 + _2
Следовательно, нет никакого синтаксического ключевого слова для lambda-выражений в C++. Использование метки-заполнителя как операнда подразумевает, что вызов оператора - lambda-выражение. Однако, это истинно только для вызовов оператора. Выражения лямбды, содержащие вызовы функций, управляющие структуры, приведения и т.д. требуют специальных синтаксических конструкций. Что наиболее важно, функциональные вызовы должны быть обернуты в bind-функции. Как пример, рассмотрим lambda-выражение:
lambda x y.foo(x,y)
вовсе не foo(_1, _2), C++-копия этого выражения:
bind(foo, _1, _2)
Обращаем Ваше внимание на этот тип lambda-выражений C++, как bind-выражений. Lambda-выражение определяет функтор C++, следовательно синтаксис функциональных приложений походит на вызов любого другого функтора, например: (_1 + _2)(i, j).
Полную документацию и примеры использования можно найти в оригинальной документации:
http://www.boost.org/doc/html/lambda.html