#include <boost/phoenix/scope/lambda.hpp>
Много раз вам нужно написать ленивую функцию, которая принимает одну или несколько функций (функции более высокого порядка). Например, на ум приходят алгоритмы STL. Рассмотрим ленивую версию<stl::for_each
>:
struct for_each_impl
{
template <typename C, typename F>
struct result
{
typedef void type;
};
template <typename C, typename F>
void operator()(C& c, F f) const
{
std::for_each(c.begin(), c.end(), f);
}
};
function<for_each_impl> const for_each = for_each_impl();
Обратите внимание, что функция принимает другую функцию<f
>в качестве аргумента. Объем этой функции,<f
>, ограничен в пределах<operator()
>. Когда<f
>называется внутри<std::for_each
>, он существует в новой области, наряду с новыми аргументами и, возможно, локальными переменными. Эта новая область вовсе не связана с внешними областями за пределами<operator()
>.
Простой синтаксис:
lambda
[
lambda-body
]
Как и<let
>, могут быть объявлены локальные переменные, позволяющие 1. N локальных переменных объявлений (где N ==<BOOST_PHOENIX_LOCAL_LIMIT
>:
lambda(local-declarations)
[
lambda-body
]
Аналогичные ограничения применяются в отношении сферы охвата и видимости. RHS (ламбда-выражение правой стороны) каждой локальной декларации не может относиться к любому локальному идентификатору LHS. Локальные идентификаторы еще не в области; они будут в области только в области лямбда-тела:
lambda(
_a = 1
, _b = _a
)
Смотри<let
>Для получения дополнительной информации.
Пример: Используя наш ленивый<for_each
>давайте напечатаем все элементы в контейнере:
for_each(arg1, lambda[cout << arg1])
Что касается аргументов (arg1..argN), то область, в которой существует лямбда-тело, совершенно нова. Слева<arg1
>относится к аргументу, переданному<for_each
>(контейнер).<arg1
>относится к аргументу, переданному<std::for_each
>, когда мы, наконец, можем назвать<operator()
>в нашем<for_each_impl
>выше (элемент контейнера).
Тем не менее, мы можем захотеть получить информацию из внешних областей. Хотя у нас нет доступа к аргументам во внешних областях, у нас все еще есть доступ к локальным переменным из внешних областей. Мы можем передавать информацию, связанную с аргументами, только из внешних<lambda
>областей через локальные переменные.
![[Note]](/img/note.png) |
Note |
Это принципиальное различие между<let >и<lambda >:<let >не вводит новых аргументов;<lambda >делает. |
Другой пример: Пользуясь нашим ленивым<for_each
>и ленивым<push_back
>:
struct push_back_impl
{
template <typename C, typename T>
struct result
{
typedef void type;
};
template <typename C, typename T>
void operator()(C& c, T& x) const
{
c.push_back(x);
}
};
function<push_back_impl> const push_back = push_back_impl();
Напишите лямбда-выражение, которое принимает:
- 2-мерный контейнер (например,<
vector<vector<int>>
>)
- элемент контейнера (например,<
int
>)
В каждой из них (28).
Решение:
for_each(arg1,
lambda(_a = arg2)
[
push_back(arg1, _a)
]
)
Поскольку мы не имеем доступа к аргументам внешних сфер за пределами лямбда-тела, мы вводим локальную переменную<_a
>, которая фиксирует второй внешний аргумент:<arg2
>. Следовательно, _a = arg2. Эта локальная переменная видна внутри области лямбда.
lambda.cpp