Что такое лямбда функции c
Перейти к содержимому

Что такое лямбда функции c

  • автор:

Что такое лямбда функции c

Лямбда-выражения представляют упрощенную запись анонимных методов. Лямбда-выражения позволяют создать емкие лаконичные методы, которые могут возвращать некоторое значение и которые можно передать в качестве параметров в другие методы.

Ламбда-выражения имеют следующий синтаксис: слева от лямбда-оператора => определяется список параметров, а справа блок выражений, использующий эти параметры:

(список_параметров) => выражение

С точки зрения типа данных лямбда-выражение представляет делегат. Например, определим простейшее лямбда-выражение:

Message hello = () => Console.WriteLine("Hello"); hello(); // Hello hello(); // Hello hello(); // Hello delegate void Message();

В данном случае переменная hello представляет делегат Message — то есть некоторое действие, которое ничего не возвращает и не принимает никаких параметров. В качестве значения этой переменной присваивается лямбда-выражение. Это лямбда-выражение должно соответствовать делегату Message — оно тоже не принимает никаких параметров, поэтому слева от лямбда-оператора идут пустые скобки. А справа от лямбда-оператора идет выполняемое выражение — Console.WriteLine(«Hello»)

Затем в программе можно вызывать эту переменную как метод.

Если лямбда-выражение содержит несколько действий, то они помещаются в фигурные скобки:

Message hello = () => < Console.Write("Hello "); Console.WriteLine("World"); >; hello(); // Hello World

Выше мы определили переменную hello, которая представляет делегат Message. Но начиная с версии C# 10 мы можем применять неявную типизацию (определение переменной с помощью оператора var ) при определении лямбда-выражения:

var hello = () => Console.WriteLine("Hello"); hello(); // Hello hello(); // Hello hello(); // Hello

Но какой тип в данном случае представляет переменная hello? При неявной типизации компилятор сам пытается сопоставить лямбда-выражение на основе его опеределения с каким-нибудь делегатом. Например, выше определенное лямбда-выражение hello по умолчанию компилятор будет рассматривать как переменную встроенного делегата Action , который не принимает никаких параметров и ничего не возвращает.

Параметры лямбды

При определении списка параметров мы можем не указывать для них тип данных:

Operation sum = (x, y) => Console.WriteLine($" + = "); sum(1, 2); // 1 + 2 = 3 sum(22, 14); // 22 + 14 = 36 delegate void Operation(int x, int y);

В данном случае компилятор видит, что лямбда-выражение sum представляет тип Operation, а значит оба параметра лямбды представляют тип int . Поэтому никак проблем не возникнет.

Однако если мы применяем неявную типизацию, то у компилятора могут возникнуть трудности, чтобы вывести тип делегата для лямбда-выражения, например, в следующем случае

var sum = (x, y) => Console.WriteLine($" + = "); // ! Ошибка

В этом случае можно указать тип параметров

var sum = (int x, int y) => Console.WriteLine($" + = "); sum(1, 2); // 1 + 2 = 3 sum(22, 14); // 22 + 14 = 36

Если лямбда имеет один параметр, для которого не требуется указывать тип данных, то скобки можно опустить:

PrintHandler print = message => Console.WriteLine(message); print("Hello"); // Hello print("Welcome"); // Welcome delegate void PrintHandler(string message);

Возвращение результата

Лямбда-выражение может возвращать результат. Возвращаемый результат можно указать после лямбда-оператора:

var sum = (int x, int y) => x + y; int sumResult = sum(4, 5); // 9 Console.WriteLine(sumResult); // 9 Operation multiply = (x, y) => x * y; int multiplyResult = multiply(4, 5); // 20 Console.WriteLine(multiplyResult); // 20 delegate int Operation(int x, int y);

Если лямбда-выражение содержит несколько выражений (или одно выражение в фигурных скобках), тогда нужно использовать оператор return , как в обычных методах:

var subtract = (int x, int y) => < if (x >y) return x - y; else return y - x; >; int result1 = subtract(10, 6); // 4 Console.WriteLine(result1); // 4 int result2 = subtract(-10, 6); // 16 Console.WriteLine(result2); // 16

Добавление и удаление действий в лямбда-выражении

Поскольку лямбда-выражение представляет делегат, тот как и в делегат, в переменную, которая представляет лямбда-выражение можно добавлять методы и другие лямбды:

var hello = () => Console.WriteLine("METANIT.COM"); var message = () => Console.Write("Hello "); message += () => Console.WriteLine("World"); // добавляем анонимное лямбда-выражение message += hello; // добавляем лямбда-выражение из переменной hello message += Print; // добавляем метод message(); Console.WriteLine("--------------"); // для разделения вывода message -= Print; // удаляем метод message -= hello; // удаляем лямбда-выражение из переменной hello message?.Invoke(); // на случай, если в message больше нет действий void Print() => Console.WriteLine("Welcome to C#");
Hello World METANIT.COM Welcome to C# -------------- Hello World

Лямбда-выражение как аргумент метода

Как и делегаты, лямбда-выражения можно передавать параметрам метода, которые представляют делегат:

int[] integers = < 1, 2, 3, 4, 5, 6, 7, 8, 9 >; // найдем сумму чисел больше 5 int result1 = Sum(integers, x => x > 5); Console.WriteLine(result1); // 30 // найдем сумму четных чисел int result2 = Sum(integers, x => x % 2 == 0); Console.WriteLine(result2); //20 int Sum(int[] numbers, IsEqual func) < int result = 0; foreach (int i in numbers) < if (func(i)) result += i; >return result; > delegate bool IsEqual(int x);

Метод Sum принимает в качестве параметра массив чисел и делегат IsEqual и возвращает сумму чисел массива в виде объекта int. В цикле проходим по всем числам и складываем их. Причем складываем только те числа, для которых делегат IsEqual func возвращает true. То есть делегат IsEqual здесь фактически задает условие, которому должны соответствовать значения массива. Но на момент написания метода Sum нам неизвестно, что это за условие.

При вызове метода Sum ему передается массив и лямбда-выражение:

int result1 = Sum(integers, x => x > 5);

То есть параметр x здесь будет представлять число, которое передается в делегат:

if (func(i))

А выражение x > 5 представляет условие, которому должно соответствовать число. Если число соответствует этому условию, то лямбда-выражение возвращает true, а переданное число складывается с другими числами.

Подобным образом работает второй вызов метода Sum, только здесь уже идет проверка числа на четность, то есть если остаток от деления на 2 равен нулю:

int result2 = Sum(integers, x => x % 2 == 0);

Лямбда-выражение как результат метода

Метод также может возвращать лямбда-выражение. В этом случае возвращаемым типом метода выступает делегат, которому соответствует возвращаемое лямбда-выражение. Например:

Operation operation = SelectOperation(OperationType.Add); Console.WriteLine(operation(10, 4)); // 14 operation = SelectOperation(OperationType.Subtract); Console.WriteLine(operation(10, 4)); // 6 operation = SelectOperation(OperationType.Multiply); Console.WriteLine(operation(10, 4)); // 40 Operation SelectOperation(OperationType opType) < switch (opType) < case OperationType.Add: return (x, y) =>x + y; case OperationType.Subtract: return (x, y) => x - y; default: return (x, y) => x * y; > > enum OperationType < Add, Subtract, Multiply >delegate int Operation(int x, int y);

В данном случае метод SelectOperation() в качестве параметра принимает перечисление типа OperationType. Это перечисление хранит три константы, каждая из которых соответствует определенной арифметической операции. И в самом методе в зависимости от значения параметра возвращаем определенное лямбда-выражение.

Лямбда-функции в C++

Лямбда-функции появились в C++11. Они представляют собой анонимные функции, которые можно определить в любом месте программы, подходящем по смыслу.

Приведу пример простейшей лямбда функции:

auto myLambda = []()< std::cout ; myLambda(); 

Выражение auto myLambda означает объявление переменной с автоматически определяемым типом. Крайне удобная конструкция C++11, которая позволяет сделать ваш код более лаконичным и устойчивым к изменениям. Настоящий тип лямбда-функции слишком сложный, поэтому набирать его нецелесообразно.

Непосредственное объявление лямбда-функции []() < std::cout состоит из трех частей. Первая часть (квадратные скобки [] ) позволяет привязывать переменные, доступные в текущей области видимости. Вторая часть (круглые скобки () ) указывает список принимаемых параметров лямбда-функции. Третья часть (в фигурных скобках <> ) содержит тело лямбда-функции.

Вызов определенной лямбда-функции ничем не отличается от вызова обычной функции: myLambda() . В нашем случае на консоль будет выведено сообщение:

"Hello, lambda!"

Прежде, чем перейти к более сложным примерам лямбда-функций, определим вспомогательную шаблонную функцию:

template < typename Func >void call( Func func )

В качестве аргумента она принимает любой объект, который можно вызвать с аргументом -5 . Более подробно о создании таких функций мы говорили, когда рассматривали указатели на функции в C++. Мы будем передавать в call() наши лямбда-функции для запуска.

Сначала просто выведем переданное лямбда-функции значение:

call( []( int val ) < // Параметр val == -5, т.е. соответствует переданному значению std::cout -5 > ); 

Теперь рассмотрим возможность "замыкания", т.е. передадим в лямбда-функцию значение локальной переменной по значению:

int x = 5; call( [ x ]( int val ) < // x == 5, но параметр передается по значению std::cout 0 // x = val; - Не компилируется. Изменять значение x мы не можем > ); 

Но если мы хотим изменить значение переменной внутри лямбда-функции, то можем передать его по ссылке:

int x = 33; call( [ &x ]( int val ) < // Теперь x передается по ссылке std::cout 33 x = val; // OK! std::cout -5 > ); // Значение изменилось: std::cout -5 

Обратите внимание на побочный эффект от связывания переменных с лямбда-функцией по ссылке:

int x = 5; auto refLambda = [ &x ]()< std::cout ; refLambda(); // --> 5 x = 94; // Значение поменялось, что скажется и на лямбда-функции! refLambda(); // --> 94 

Будьте особенно аккуратны с привязкой параметров по ссылке, когда работаете с циклами. Чтобы не получилось, что все созданные лямбда-функции работали с одним и тем же значением, когда должны иметь собственные копии.

Привязку можно осуществлять по любому числу переменных, комбинируя как передачу по значению, так и по ссылке:

int y = 55; int z = 94; call( [ y, &z ]( int val ) < std::cout 55 std::cout 94 // y = val; - Нельзя z = val; // OK! > ); 

Если требуется привязать сразу все переменные, то можно использовать следующие конструкции:

call( // Привязываем все переменные в области видимости по значению [ = ]( int val ) < /* … */ >); call( // Привязываем все переменные в области видимости по ссылке [ & ]( int val ) < /* … */ >); 

Допустимо и комбинирование:

int x = 21; int y = 55; int z = 94; int w = 42; call( // Привязываем x по значению, а все остальное по ссылке [ &, x ]( int val ) < /* … */ >); call( // Привязываем y по ссылке, а все остальное по значению [ =, &y ]( int val ) < /* … */ >); call( // Привязываем x и w по ссылке, а все остальное по значению [ =, &x, &w ]( int val ) < /* … */ >); 

Однако замечу, что на практике лучше не использовать обобщенное привязывание через = и & , а явно обозначать необходимые переменные по одной. Иначе могут возникнуть загадочные ошибки из-за конфликтов имен.

Когда использовать лямбда-функции?

Один из лучших примеров правильного использования лямбда-функций связан с библиотекой алгоритмов stl . Большинство функций этой библиотеки принимают аргумент-предикат. Такой аргумент позволяет контролировать те или иные аспекты алгоритма.

Конечно, этот аргумент не обязан быть лямбда-функцией, но часто их применение оказывается оправданным. Например:

std::vector < int >v = < 2, 4, 5, 6, 7, 9, 11, 14 >; auto end = std::remove_if( v.begin(), v.end(), []( int x ) < return x % 2 == 0; >); std::for_each( v.begin(), end, []( int x ) < std::cout ); 

Этот код интуитивно понятен, поэтому вы сами с ним легко разберетесь без моих пояснений. Приведу лишь то, что он выведет на консоль:

5 7 9 11

В своих программах вы тоже можете создавать универсальные функции, для которых управление ходом выполнения осуществляется с помощью функциональных объектов и лямбда-функций в частности.

Похожие публикации

QClipboard: Использование буфера обмена в Qt

Односвязный список на C++

Комплексные числа в C++

Структура Qt-проекта на C++

Python vs C++: Алгоритм решения судоку

QListWidget: Примеры использования

Модель-представление в Qt

Диалоговые окна в Qt: Модальные и немодальные

Комментарии

Anonymous

"Интуитивно понятна" - это inline функция. А нахрена заморачиваться со всякими лямбда - нифига не понятно. Хотя для "говнокода" - в самый раз. Имхо.

Mikhail

"Интуитивно понятна" - это inline функция. А нахрена заморачиваться со всякими лямбда - нифига не понятно. Хотя для "говнокода" - в самый раз. Имхо.

Согласен, что пример несколько притянут. Может потом подберу более подходящий. Приведенный является вариацией примера для std::remove_if с cplusplus.com.

А если речь идет о том, что лямбда-функции не нужны вовсе, то технически это, конечно, так. В конце концов, всегда можно создать функтор. Однако замыкание в комбинации с лямбда-функциями позволяет сделать код менее многословным.

Anonymous

Лямда фнкция дает искушение написать оные 100500 раз в коде программы и превратить оную в превдосложный-мегакод. Вместо того, чтобы написать отдельно функцию, мы ее "по-быстрому" слабаем в теле другой функции. По принципу; "не успеваю сделать нормально - план горит". Имхо.

Mikhail

Лямда фнкция дает искушение написать оные 100500 раз в коде программы и превратить оную в превдосложный-мегакод. Вместо того, чтобы написать отдельно функцию, мы ее "по-быстрому" слабаем в теле другой функции. По принципу; "не успеваю сделать нормально - план горит". Имхо.

Ну да. Тут, как и в любом деле, нужно знать меру. Если можно написать более общее решение, которое получится использовать в коде многократно, то так и следует поступать.

В частности, для примера из статьи с проверкой на четность можно создать функтор на подобии IsDivisibleBy. Чтобы использовать его по нужному месту с аргументом:

std::remove_if( v.begin(), v.end(), IsDivisibleBy< int >( 2 ) );

В этом смысле злоупотребление лямбда-функциями аналогично использованию "волшебных чисел". С другой стороны, если есть уверенность, что требуется очень специфическая функция, которая больше в коде нигде не понадобится в обозримом будущем, то лямбдой вполне можно обойтись (например, для какого-нибудь callback'а). Хотя, конечно, все часто идет не по плану, и функция где-нибудь может понадобиться вновь. В этом случае дублированием заниматься неуместно, и без рефакторинга не обойтись.

Что такое лямбда функции c

Кто может человеческим языком объяснить, зачем в С++ 11 ввели лямбда-выражения?
Что это вообще такое и какая в них необходимость?

Re: Зачем нужны лямбда-выражения?

От: rg45
Дата: 23.10.12 14:52
Оценка:

Здравствуйте, Аноним, Вы писали:

А>Кто может человеческим языком объяснить, зачем в С++ 11 ввели лямбда-выражения?
А>Что это вообще такое и какая в них необходимость?

Грубо говоря, это функциональные объекты, которые можно определить непосредственно в контексте вызывающей функции, не определяя никаких новых классов.

--
C++ уже затем учить надо, что он ум в порядок приводит. (с) Ломоносов М.В.
Re: Зачем нужны лямбда-выражения?

От: nen777w
Дата: 23.10.12 15:13
Оценка:

А>Кто может человеческим языком объяснить, зачем в С++ 11 ввели лямбда-выражения?
А>Что это вообще такое и какая в них необходимость?

Анонимные функциональные объекты (т.е. объект который ведет себя как функция), ну может и не совсем анонимные (но чаще используются именно так), т.е. их можно определить прямо в том месте где они нужны.
Позволяет избежать написания функций/функторов которые по сути нужны только в конкретном месте кода и больше нигде (но это частный случай конечно, но наиболее распространенный для применения лямбд).
Хотя к слову сказать в boost 1.50 появилась ещё более крутая (в плане синтаксиса её определения) штука — локальные функции.

Re: Зачем нужны лямбда-выражения?

От: maloi_alex
Дата: 23.10.12 15:18
Оценка:

Здравствуйте, Аноним, Вы писали:

Ну просто просто чтобы для математиков оперировать функциями как им более удобно.

Re: Зачем нужны лямбда-выражения?

От: Константин
Дата: 23.10.12 15:27
Оценка: 1 (1) +1

Здравствуйте, Аноним, Вы писали:

А>Кто может человеческим языком объяснить, зачем в С++ 11 ввели лямбда-выражения?
А>Что это вообще такое и какая в них необходимость?

1. Это позволяет писать библиотеки с человеческим синтаксисом без макросов. Пример для параллельной обработки элементов массива

parallel_for_each( begin(a), end(a), [&](int n ) < if (is_prime(n)) InterlockedIncrement(&prime_count); >);

2. Это то, что, наконец делает удобным для использования стандартных алгоритмов из C++ standard library:

 std::sort( someList.begin(), someList.end(), [] (Elem* t1, Elem* t2) < return t1->getID() < t2->getID(); > );
// 100 lines upper // WTF this class is for. // make std::sort happy :) struct CompareById < bool operator() ( Elem* t1, Elem* t2 ) < return t1->getID() < t2->getID(); > >; /// A lot of other code /// A lot of other code /// A lot of other code /// A lot of other code /// A lot of other code /// A lot of other code /// A lot of other code /// A lot of other code /// A lot of other code /// A lot of other code /// A lot of other code /// A lot of other code /// A lot of other code /// A lot of other code /// A lot of other code /// A lot of other code /// A lot of other code /// A lot of other code /// A lot of other code /// A lot of other code std::sort(someList.begin(), someList.end(), CompareById() );

Re[2]: Зачем нужны лямбда-выражения?

От: Константин
Дата: 23.10.12 15:35
Оценка:

Здравствуйте, nen777w, Вы писали:

А>>Кто может человеческим языком объяснить, зачем в С++ 11 ввели лямбда-выражения?
N>Хотя к слову сказать в boost 1.50 появилась ещё более крутая (в плане синтаксиса её определения) штука — локальные функции.

Казалось бы, что разница не велика. Лямбда даже немного лаконичней. Пример из документации

 auto add = [factor, &sum](int num) < // C++11 only. sum += factor * num; >; void BOOST_LOCAL_FUNCTION(const bind factor, bind& sum, int num) < sum += factor * num; >BOOST_LOCAL_FUNCTION_NAME(add)

Re: Зачем нужны лямбда-выражения?

От: Vamp
Дата: 23.10.12 15:46
Оценка: 1 (1) +3

А>Кто может человеческим языком объяснить, зачем в С++ 11 ввели лямбда-выражения?
А>Что это вообще такое и какая в них необходимость?
Пришли из функциональных языков. В НЕКОТОРЫХ СЛУЧАЯХ позволяют писать более лаконичные программы, но часто служат исключительно целям запутывания. Особенно помогает совершенно зубодробительный синтаксис.

Да здравствует мыло душистое и веревка пушистая.
Re[2]: Зачем нужны лямбда-выражения?

От: Warturtle
Дата: 23.10.12 16:43
Оценка:

Здравствуйте, Vamp, Вы писали:

А>>Кто может человеческим языком объяснить, зачем в С++ 11 ввели лямбда-выражения?
А>>Что это вообще такое и какая в них необходимость?
V>Пришли из функциональных языков. В НЕКОТОРЫХ СЛУЧАЯХ позволяют писать более лаконичные программы, но часто служат исключительно целям запутывания. Особенно помогает совершенно зубодробительный синтаксис.
В VC++ уже давно можно было параметризовать шаблонные функции локальными классами, поэтому там можно обойтись и обычным синтаксисом. Только вот "контекст" надо явно передавать (не видит ничего из "окружающей" функции, но это иногда и неплохо). Пример без шаблонов (вызываем что-то по таймеру), где все в одной функции:

LRESULT SomeWindow::OnActionMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled) < struct Impl < static void CALLBACK Do(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) < typedef boost::function< void () > ActionT; boost::scoped_ptr < ActionT >action( reinterpret_cast< ActionT * >( ::GetWindowLongPtr(hwnd, GWLP_USERDATA) ) ); (*action)(); ::KillTimer(hwnd, 12345); > >; this->SetWindowLongPtr(GWLP_USERDATA, lParam); this->SetTimer(12345, 1000, &Impl::Do); return 0; >

— короче, локальные классы тоже заруливают, особенно если нету лямбд.
Re[2]: Зачем нужны лямбда-выражения?

От: Nikita.Trophimov
Дата: 23.10.12 18:56
Оценка:

N>Хотя к слову сказать в boost 1.50 появилась ещё более крутая (в плане синтаксиса её определения) штука — локальные функции

Объяснить сможете, пожалуйста, чем они Вам больше нравятся в этом плане?

Re: Зачем нужны лямбда-выражения?

От: elmal
Дата: 23.10.12 19:15
Оценка: 1 (1) +1 -1

Здравствуйте, Аноним, Вы писали:

А>Что это вообще такое и какая в них необходимость?
В настоящее время, учитывая, что достигли практически потолка по тактовой частоте и дальше идет рост количества ядер, появилась мода на параллелизм. В результате снова в моде стал функциональный подход, так как он очень хорошо работает в условиях concurrency и не требует явных синхронизаций. И сейчас в нормальных вузах усиленно думают, как задействовать растущее число ядер процессора и как обеспечить автоматическое распараллеливание, в результате снова в моде функциональное программирование. А в функциональном программировании практически основа всего — лямбда. Если есть лямбда — можно уже на любом языке и ООП реализовывать и тому подобное, но это уже отвлеклись. Так вот, учитывая, что функциональные языки сейчас переживают второе рождение, ибо снова с однопроцессорных десктопов по существу перешли на многопроцессорные мейнфреймы, было бы странным, если бы функциональщину не добавляли во все мейнстримовые языки. Дошло и до плюсов, собственно. Плюсы — язык, поддерживающий много парадигм, и было бы странным, если б у него не стало поддержки функциональщины. Хоть и синтаксический сахар, и это можно было реализовать и раньше, но сейчас просто стало удобно и лямбды стали востребованы сообществом.

Re[2]: Зачем нужны лямбда-выражения?

От: Кодт
Дата: 23.10.12 20:35
Оценка: 44 (4)

Здравствуйте, elmal, Вы писали:

E>Здравствуйте, Аноним, Вы писали:

А>>Что это вообще такое и какая в них необходимость?
E>В настоящее время, учитывая, что достигли практически потолка по тактовой частоте и дальше идет рост количества ядер, появилась мода на параллелизм. В результате снова в моде стал функциональный подход, так как он очень хорошо работает в условиях concurrency и не требует явных синхронизаций. И сейчас в нормальных вузах усиленно думают, как задействовать растущее число ядер процессора и как обеспечить автоматическое распараллеливание, в результате снова в моде функциональное программирование. А в функциональном программировании практически основа всего — лямбда. Если есть лямбда — можно уже на любом языке и ООП реализовывать и тому подобное, но это уже отвлеклись. Так вот, учитывая, что функциональные языки сейчас переживают второе рождение, ибо снова с однопроцессорных десктопов по существу перешли на многопроцессорные мейнфреймы, было бы странным, если бы функциональщину не добавляли во все мейнстримовые языки. Дошло и до плюсов, собственно. Плюсы — язык, поддерживающий много парадигм, и было бы странным, если б у него не стало поддержки функциональщины. Хоть и синтаксический сахар, и это можно было реализовать и раньше, но сейчас просто стало удобно и лямбды стали востребованы сообществом.

Если хочешь обратить внимание на первоисточники, так прямо и скажи: слово "лямбда" происходит от лямбда-исчисления Чёрча, которое входит в основу функционального программирования. (Не являясь безусловно обязательной основой, тем не менее. Альтернативой, например, служит комбинаторная логика).

Зачем вообще нужно ФП — тут много доводов, не только мода на параллелизм и зажратость ресурсами. (Напомню, что Лисп появился в 1958 году, когда ещё на перфокартах работали).

Лямбда — это просторечивое название лямбда-выражения, т.е. безымянной функции.
Его главные особенности:
1) Оно безымянное, то есть не вводит новых имён в имеющееся пространство (не захламляет его).
2) Будучи выражением, может зависеть от внешних (по отношению к себе) данных — связывает их. При этом интерфейсная часть — сигнатура функции — эту связь не обозначает. Тому, кто будет вызывать лямбду, безразлично, что и как она связывает.
3) Будучи выражением, а не стейтментом, — может входить в состав других выражений, а не требовать отдельной строки программы. Резко уменьшается дистанция между точкой определения и точкой использования. Более того, лямбда-выражение можно сконструировать из других лямбда-выражений, и тут мы приближаемся к ещё одному мощному выразительному средству — функциям высшего порядка и комбинаторной логике.

ФП-программисты шутят, что объекты — это лямбды для бедных, а лямбды — это объекты для бедных.
И действительно, можно считать, что тип лямбда-выражения — это интерфейс с единственным методом, а конкретное лямбда-выражение — это объект-наследник этого интерфейса, возможно содержащий какие-то члены-данные (связанные переменные) и (пере)определяющий этот метод.
С другой стороны, интерфейс с множеством виртуальных функций можно представить себе как структуру с членами — лямбда-выражениями, каждое из которых сформулировано в конструкторе класса-наследника и связано со структурой, содержащей данные объекта этого класса.
Но это, конечно, крайности и, зачастую, либо придурь, либо от безысходности. Если язык позволяет делать и интерфейсы, и лямбды, то можно по месту выбрать то, что более подходит.

Перекуём баги на фичи!
Re[3]: Зачем нужны лямбда-выражения?

От: nen777w
Дата: 25.10.12 12:47
Оценка:

Здравствуйте, Константин, Вы писали:

К>Здравствуйте, nen777w, Вы писали:

А>>>Кто может человеческим языком объяснить, зачем в С++ 11 ввели лямбда-выражения?
N>>Хотя к слову сказать в boost 1.50 появилась ещё более крутая (в плане синтаксиса её определения) штука — локальные функции.

К>Казалось бы, что разница не велика. Лямбда даже немного лаконичней.
Ну для С++11 да, я просто когда это дописывал имел в виду просто С++, хотя и в этом случае можно лямбды писать на boost::phoenix, ( получается тоже красиво правда почему не компилябельно под iOS 🙁

Автор: nen777w
Дата: 27.05.12

), ну а на крайняк, на чистом boost::mpl, но это для любителей, хотя если разобраться (а я разобрался потратив пару часов

Автор: nen777w
Дата: 07.05.11
) то на самом деле не так уж и страшно.
Re[2]: Зачем нужны лямбда-выражения?

От: Aлeкceй
Дата: 25.10.12 19:29
Оценка:

Здравствуйте, Константин, Вы писали:

К>parallel_for_each( begin(a), end(a), [&](int n ) < К>if (is_prime(n)) К> InterlockedIncrement(&prime_count); К> >); К>

Чего-то они как-то намудрили опять с синтаксисом. Неужели иначе нельзя было?

Re[3]: Зачем нужны лямбда-выражения?

От: Константин
Дата: 26.10.12 10:01
Оценка: 1 (1) -1

Здравствуйте, Aлeкceй, Вы писали:

A>Чего-то они как-то намудрили опять с синтаксисом. Неужели иначе нельзя было?

Думаю, что сильно проще всё равно не было бы:

Эта часть почти обязательная: тело + тип входного параметра. Разве что можно было бы наверное как-то исключить имя типа (сделать что-то типа шаблонной лямбды)

( int n ) < if (is_prime(n)) InterlockedIncrement(&prime_count); >

Блок с указанием как захватывать внешние переменные теоретически можно было бы исключить, но в c++ умение делать выбор передавать по значению или по ссылке критично, поэтому пришлось бы изобрести некий аналог как передать эту информацию

Так что синтаксического мусора не так и много

Re[3]: Зачем нужны лямбда-выражения?

От: pik
Дата: 26.10.12 10:13
Оценка:

Здравствуйте, Aлeкceй, Вы писали:

A>Чего-то они как-то намудрили опять с синтаксисом. Неужели иначе нельзя было?

если до этого boost-ом полъзовались то лямбда это уж совесем не мудрость а очень просто и понятно

Re[2]: Зачем нужны лямбда-выражения?

От: ДимДимыч http://klug.org.ua
Дата: 26.10.12 12:35
Оценка:

Здравствуйте, nen777w, Вы писали:

N>Хотя к слову сказать в boost 1.50 появилась ещё более крутая (в плане синтаксиса её определения) штука — локальные функции.

Nested functions и в gcc есть в качестве расширения.

Лямбда функции и указатели на функции в классе

Сначала проблема была с вызовом func из funcTest, но я вроде нашел решение и переписал эту строчку: int (*funcTest)(int value) = [&](int value) ; , но появилась проблема: не существует подходящей функции преобразования из "lambda []int (int value)->int" в "int (*)(int value)" Подскажите пожалуйста как правильно реализовать, то что мне требуется. И буду благодарен если, кто нибудь поделится ссылкой на источник, в котором понятным языком рассказывается о лямбда функциях и подобной теме.

Отслеживать

218k 15 15 золотых знаков 117 117 серебряных знаков 229 229 бронзовых знаков

задан 28 ноя 2020 в 14:10

Павел Ериков stand with Russia Павел Ериков stand with Russia

5,650 1 1 золотой знак 12 12 серебряных знаков 31 31 бронзовый знак

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *