for_each ( veclntegers.begin ()
, veclntegers.end
|
()
|
//
|
Конец диапазона
|
, DisplayElement
|
() );
|
// Объект
|
унарной функции
|
Лямбда-выражение уплотняет весь код, включая определение объекта функции, до трех строк:
Отобразить массив целых чисел, используя лямбда-выражения for_each ( veclntegers.begin () // Начало диапазона
,
|
veclntegers.end
|
()
|
//
|
Конец диапазона
|
} );
|
,
|
[](int& Element)
|
{cout «
|
element « '
|
|
|
|
|
|
// Лямбда-выражение
|
Когда компилятор встречает лямбда-выражение, в данном случае такое:
[](int Element) {cout
|
« element
|
« '
|
}
|
он автоматически
|
разворачивает
|
его в
|
представление, подобное структуре
|
D is p la y E le m e n t< in t> :
|
|
|
|
struct NoName
|
|
|
|
|
{
|
()
|
(const int&
|
element)
|
const
|
void operator
|
{
cout << element « ' ';
Как определить лямбда-выражение
О пределение лямбда-выражения должно начинаться с квадратных скобок ([ ]).
Эти скобки, по существу, говорят компилятору, что началось лямбда-выражение. Они
Лямбда-выражение для унарной функции
|
501
|
сопровождаются списком параметров, являющимся тем же списком параметров, который вы предоставили бы своей реализации оператора o p e r a t o r (), если бы не использовали лямбда-выражение.
Лямбда-выражение для унарной функции
Лямбда-версия унарного оператора o p e r a t o r (Т у р е ), получающего один параметр, имела бы следующий вид:
[](Type paramName) { // здесь код лямбда-выражения; }
Обратите внимание, что по мере необходимости параметр можно передать по ссылке:
[](Types paramName) { // здесь код лямбда-выражения; }
Листинг 22.1 поможет изучить применение лямбда-функции для отображения содер жимого контейнера стандартной библиотеки шаблонов (STL) с использованием алгоритма f o r _ e a c h ().
ЛИСТИНГ 22.1. Отображение элементов контейнера при помощи алгоритма for_each (), который вызывается лямбда-выражением, а не объектом функции______________________
#include
#include
#include
#include
4:
using namespace std;
6 :
int main ()
{
vector veclntegers;
1 0 :
for (int nCount = 0; nCount < 10; ++ nCount)
veclntegers.push_back (nCount);
13:
list listChars;
for (char nChar = 'a'; nChar < 'k'; ++nChar)
listChars.push_back (nChar);
17:
cout « "Displaying vector of integers using a lambda: " « endl;
// Отобразить массив целыхчисел
for_each ( veclntegers.begin () // Начало диапазона
22:
|
,
|
veclntegers.end
|
()
|
//
|
Конец диапазона
|
23:
|
,
|
[](int& element)
|
{cout «
|
element « ' '; } );
|
24:
|
|
|
|
// лямбда
|
|
|
|
|
|
cout « endl « endl;
cout « "Displaying list of characters using a lambda: " « endl;
27
28// Отобразить список символов
502
|
ЗАНЯТИЕ 22. Лямбда-выражения языка С++11
|
29
|
for each { listChars.begin ()
|
/ /
|
Начало диапазона
|
30
|
, listChars.end ()
|
/ /
|
Конец диапазона
|
31
|
, [ ] (char& element)
|
{cout « element «
|
|
|
/ /
|
лямбда
|
32
cout « endl;
return 0;
}
Результат
Displaying vector of integers using a lambda:
0123456789
Displaying list of characters using a lambda:
a b c d e f g h i j
Анализ
Интерес представляют два лямбда-выражения в строках 23 и 31. Они очень похожи, если бы не тип входного параметра, поскольку они были приспособлены к характеру эле ментов в этих двух контейнерах. Первое получает один параметр типа i n t , поскольку оно используется для отображения одного элемента за раз из вектора целых чисел, тогда как второе получает параметр типа c h a r, поскольку предназначен для отображения элементов типа c h a r, хранящихся в контейнере s t d : : l i s t .
ПРИМЕЧАНИЕ
|
Вывод листинга 22.1 вовсе не случайно совпадает с выводом листинга 21.1.
|
Фактически эта программа - лямбда-версия листинга 21.1, где был использо
|
|
|
ван объект функции DisplayElement.
|
|
Сравнивая эти два листинга, можно придти к выводу, что у лямбда-функций есть
|
|
серьезный потенциал, позволяющий сделать код C++ проще и компактней.
|
Лямбда-выражение для унарного предиката
Предикат позволяет принимать решения. Унарный предикат — это унарное выраже ние, которое возвращает значение типа b o o l ( t r u e или f a ls e ) . Лямбда-выражения также могут возвращать значения. Например, следующее лямбда-выражение возвращает значе ние t r u e для четных чисел:
[](int& Num) {return {(Num % 2) == 0); }
Характер возвращаемого значения в данном случае указывает компилятору, что лямбда-выражение возвращает тип b o o l.
Лямбда-выражение для унарного предиката
|
503
|
Вы можете использовать лямбда-выражение, являющ ееся унарным предикатом, в та ких алгоритмах, как s t d : : f i n d _ i f (), для поиска четных чисел в коллекции. Пример приведен в листинге 22.2.
Л И СТИ Н Г 2 2 .2 . Поиск четных чисел в коллекции с использованием лямбда-
выражения, унарного предиката и алгоритма std:;find if ()___________________________
#include
#include
#include
using namespace std;
5 : int main ()
6 : {
vector vecNums;
vecNums.push_back(25);
vecNums.push_back(101);
vecNums.push_back(2011);
vecNums.push_back(-50);
auto iEvenNum = find_if( ecNums.cbegin()
14:
|
,
|
vecNums.cend()
|
// диапазон
|
для
|
поиска
|
15:
|
,
|
[](const int&
|
Num){return ((Num % 2)
|
==
|
0); } );
|
16:
|
|
|
|
|
|
if (iEvenNum != vecNums.cend())
18: cout « "Even number in collection is: " « *iEvenNum
endl;
19:
return 0;
21: }
Результат
Even number in collection is: -50
Анализ
Лямбда-функция, работающая как унарный предикат, представлена в строке 15. Алго ритм f i n d _ i f () вызывает унарный предикат для каждого элемента в диапазоне. Когда предикат возвращает значение t r u e , алгоритм f i n d _ i f () сообщает о находке возвращ е нием итератора на этот элемент. В данном случае предикат (лямбда-выражение) возвраща ет значение tr u e , когда алгоритм f i n d _ i f () встречает четное целое число (т.е. результат операции деления по модулю на 2 равен нулю).
ПРИМЕЧАНИЕ
Листинг 22.2 не только демонстрирует лямбда-выражение как унарный пре дикат, но также и использование ключевого слова const в пределах лямбда-выражения.
Не забывайте использовать его для входных параметров, особенно если это ссылки.
504 ЗАНЯТИЕ 22. Лямбда-выражения языка С++11
Лямбда-выражение с состоянием
списки захвата [... ]
листинге 22.2 был создан унарный предикат, который возвращ ал значение t r u e , если целое число было делимым на 2, т.е. целое четное число. Но что если нужна более обобщенная функция, которая возвращ ает значение t r u e , если число делимо на предо ставленный пользователем делитель? Делитель необходимо содержать в выражении как “состояние” :
Do'stlaringiz bilan baham: |