Стандартная библиотека шаблонов (STL) [STL94], теперь часть C++ Стандартная библиотека [C++98], является общей библиотекой контейнеров и алгоритмов. Обычно алгоритмы STL работают на контейнерных элементах через функционные объекты. Эти функциональные объекты передаются в качестве аргументов в пользу алгоритмов.
Любая конструкция C++, которую можно назвать синтаксисом вызова функции, является объектом функции. STL содержит предопределенные функциональные объекты для некоторых распространенных случаев (например, плюс
, менее
и не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
содержит типовые определения для аргументов и видов возврата объекта функции, которые необходимы для создания объекта функции adaptable.
В дополнение к основным классам объектов функции, таким как один из вышеперечисленных, STL содержит шаблоны binder для создания неарочного объекта функции из адаптируемого объекта двойной функции путем фиксации одного из аргументов на постоянное значение. Например, вместо того, чтобы явно писать класс объектов функции, например:
class plus_1 {
int _i;
public:
plus_1(const int& i) : _i(i) {}
int operator()(const int& j) { return _i + j; }
};
эквивалентная функциональность может быть достигнута с шаблоном плюс
и одним из шаблонов связующего устройства (bind1st
). Например, следующие два выражения создают функциональные объекты с одинаковыми функциями; при ссылках оба возвращают результат добавления 1
к аргументу объекта функции:
plus_1(1)
bind1st(plus<int>(), 1)
Подэкспрессия плюс()
в последней строке является двоичным объектом функции, который вычисляет сумму двух целых чисел, и bind1st
вызывает этот объект функции частично связывающий первый аргумент к 1
. В качестве примера использования вышеуказанного объекта функции следующий код добавляет 1
к каждому элементу некоторого контейнера a
и выводит результаты в стандартный поток вывода cout
.
transform(a.begin(), a.end(), ostream_iterator<int>(cout),
bind1st(plus<int>(), 1));
Чтобы сделать шаблоны связующего более применимыми, STL содержит adaptors для создания указателей или ссылок на функции и указателей на функции-члены, адаптируемые. Наконец, некоторые реализации STL содержат функции композиции как расширения стандарта [SGI02].
Все эти инструменты направлены на одну цель: сделать возможным указать неназванные функции в вызове алгоритма STL, другими словами, передать фрагменты кода в качестве аргумента для функции. Однако эта цель достигается лишь частично. Простой приведенный выше пример показывает, что определение неназванных функций со стандартными инструментами является громоздким. Сложные выражения с участием фанкторов, адаптеров, связующих устройств и операций функционального состава, как правило, трудно понять. В дополнение к этому существуют значительные ограничения в применении стандартных инструментов. Например, стандартные связующие устройства позволяют связывать только один аргумент двоичной функции; нет связующих элементов для 3-аровых, 4-аровых и т.д.
Библиотека Boost Lambda предоставляет решения для проблем, описанных выше:
Unnamed functions can be created easily with an intuitive syntax.
The above example can be written as:
transform(a.begin(), a.end(), ostream_iterator<int>(cout),
1 + _1);
or even more intuitively:
for_each(a.begin(), a.end(), cout << (1 + _1));
Большинство ограничений в связывании аргументов удаляются, произвольные аргументы практически любой функции C++ могут быть связаны.
Отдельные операции по составу функций не нужны, так как состав функции поддерживается косвенно.
Introduction to lambda expressions
Выражение Lambda распространено на функциональных языках программирования. Их синтаксис варьируется между языками (и между различными формами lambda calculus), но основная форма лямбда выражений:
lambda x1 ... xn.e
Выражение lambda определяет неназванную функцию и состоит из:
параметры этой функции: x1... xn
.
выражение e, которое вычисляет значение функции с точки зрения параметров x1 ... xn
.
Простой пример выражения ягненка -
lambda x y.x+y
Применение функции lambda означает замену формальных параметров фактическими аргументами:
(lambda x y.x+y) 2 3 = 2 + 3 = 5
В C++ версии lambda отсутствует часть lambda x1... xn
, а официальные параметры имеют предопределенные имена. В текущей версии библиотеки есть три таких заранее определенных формальных параметра, называемых заместителями: _1
, _2
и _3
. Они ссылаются на первый, второй и третий аргумент функции, определенной выражением ламбарды. Например, C++ версия определения
lambda x y.x+y
-
_1 + _2
Следовательно, нет синтаксического ключевого слова для выражений C++ lambda. Использование владельца места в качестве операнда подразумевает, что ссылка на оператора является выражением лямбды. Однако это верно только для ссылок операторов. Выражения Ламбды, содержащие функциональные вызовы, структуры управления, касты и т.д., требуют специальных синтаксических конструкций. Самое главное, что функциональные звонки должны быть обернуты внутрь функции bind
. В качестве примера рассмотрим выражение лямбды:
lambda x y.foo(x,y)
Вместо foo(_1, _2)
, C++ для этого выражения является следующим:
bind(foo, _1, _2)
Мы ссылаемся на этот тип выражения C++ lambda как bind выражений.
Выражение lambda определяет объект функции C++, следовательно, синтаксис приложения функции похож на вызов любого другого объекта функции, например: (_1 + _2)(i, j)
.
Partial function application
Связное выражение фактически является приложением частичная функция. При частичном применении функции некоторые аргументы функции связаны с фиксированными значениями. Результатом является другая функция, с возможно меньшим количеством аргументов. При вызове с несвязанными аргументами эта новая функция вызывает оригинальную функцию с объединенным списком аргументов связанных и несвязанных аргументов.
Выражение ягненка определяет функцию. Выражение C++ lambda конструирует объект функции, фанктор, при оценке. Мы используем имя lambda functor для обозначения такого функционального объекта. Следовательно, в терминологии, принятой здесь, результат оценки выражения ягненка является ягненком-функтором.