В двух словах

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) [ STL94], теперь часть Стандартной Библиотеки C++ [ C++98], является основной библиотекой контейнеров и алгоритмов. Обычно алгоритмы STL выполняют операции над элементами контейнера через функторы. Эти функторы передаются алгоритмам в качестве аргументов. Любая конструкция C++, которая может быть вызвана с синтаксисом вызова функции, - функтор. STL содержит предопределенные функторы для некоторых общих операторов (типа 'плюс','меньше' и 'not 1'). Как пример, возможное имплементирование для шаблона стандартного плюса:

template <class T> 
struct plus : public binary_function<T, T, T>{
  T operator()(const T& i, const T& j) const { return i + j; }
};

Базовый класс binary_function<T, T, T> содержит 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<int>(), 1)

Подвыражение plus<int>() в последней строке - бинарный функтор, который вычисляет сумму двух целых чисел, и bind1st вызывает этот функтор, частично привязав первый аргумент к 1. В качестве примера использования вышеупомянутого функтора, следующий код добавляет 1 к каждому элементу некоторого контейнера a и выводит результаты в поток стандартного вывода cout.

transform(a.begin(),a.end(),ostream_iterator<int>(cout),bind1st(plus<int>(),1));

Чтобы сделать шаблоны связывания более широко применимыми, STL содержит адаптеры для выполнения указателей или ссылок на функции и указателей на функции-члены, адаптируемыми. Наконец, некоторые реализации STL содержат функциональные составные операции, как расширения Стандарта [ SGI02].

Все эти средства стремятся к одной цели: позволить определить безымянные функции в вызове алгоритма STL, другими словами, передавать фрагменты кода в качестве параметра функции. Однако, эта цель достигнута только частично. Простой пример выше показывает, что определение безымянных функций стандартными средствами является громоздким. Сложные выражения, задействующие функторы, адаптеры, биндеры(binders) и функциональные составные операции трудны для понимания. В дополнение к этому, есть существенные ограничения в применении стандартных средств. Например, стандартные биндеры позволяют связать только один аргумент бинарной функции; нет никаких биндеров для 3-х, 4-х и т.д. функций.

Boost Lambda Library обеспечивает решения, описанных выше проблем:

  • Безымянные функции могут быть созданы легко и с интуитивно-понятным синтаксисом. Вышеупомянутый пример может быть записан как:
cpp
transform(a.begin(), a.end(), ostream_iterator<int>(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

 
doc/cpp/boost/lambda.txt · Последние изменения: 2008/01/18 18:14 От clang
 
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki