C++ лямбда-вирази — одна з найкрутіших особливостей, введених у C++11, що дозволяє розробникам C++ використовувати можливості функціонального програмування. Вони спрощують код і роблять його більш лаконічним, особливо при роботі з алгоритмами. Давайте детально розглянемо лямбда-вирази, крок за кроком. 💡
🔎 Що таке лямбда-вираз?
Лямбда-вираз — це анонімна функція, визначена безпосередньо в вашому коді.
Лямбда-вирази C++ — одна з найкрутіших особливостей, що були введені в C++11, які приносять можливості функціонального програмування для розробників C++. Вони спрощують код і роблять його більш лаконічним, особливо при роботі з алгоритмами. Давайте детально розглянемо лямбда-вирази, крок за кроком. 💡
🔎 Що таке лямбда-вираз?
Лямбда-вираз — це анонімна функція, визначена безпосередньо у вашому коді.
- Чому їх використовувати?
Лямбда-вирази ідеально підходять для короткострокових завдань, таких як кастомне сортування, фільтрація або прості зворотні виклики.
🖋️ Як написати лямбда-вираз
Основний синтаксис лямбда-виразу:
[capture](parameters) -> return_type {
// body
};
Приклад:
Лямбда-вираз, що приймає ціле число і повертає подвоєне значення:
auto doubleValue = [](int x) -> int {
return x * 2;
};
// Використання:
std::cout << doubleValue(5); // Вивід: 10
[]
(capture): Визначає змінні для захоплення з навколишнього контексту.- Параметри: Як і у будь-якої функції, параметри визначаються в
()
. -> return_type
: Необов’язково; вказує тип повернення (автоматично виводиться, якщо пропущено).- Тіло: Містить логіку.
🎯 Використання лямбда-виразів з std::count_if
Функція std::count_if
з бібліотеки <algorithm>
використовує предикат (функцію, яка повертає логічне значення) для підрахунку елементів, що задовольняють умови.
Приклад: Підрахунок непарних чисел за допомогою лямбда-виразу
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> nums{1, 2, 3, 4, 5, 6};
// Лямбда для перевірки, чи є число непарним
auto isOdd = [](int x) { return x % 2 != 0; };
int count = std::count_if(nums.begin(), nums.end(), isOdd);
std::cout << "Кількість непарних елементів: " << count << "\n";
return 0;
}
🧩 Основна ідея: Лямбда-вирази надають швидкий і зручний спосіб для визначення кастомних предикатів.
🔒 Що таке захоплення в лямбда-виразах?
Захоплення дозволяє лямбда-виразам «запам’ятовувати» змінні з навколишнього контексту.
- Захоплення за значенням (
[x]
): Лямбда отримує копію змінноїx
. - Захоплення за посиланням (
[&x]
): Лямбда працює безпосередньо з оригіналом змінноїx
.
Приклад:
#include <iostream>
int main() {
int x = 10;
// Захоплення за значенням
auto captureByValue = [x]() { std::cout << "За значенням: " << x << "\n"; };
// Захоплення за посиланням
auto captureByRef = [&x]() { x += 10; std::cout << "За посиланням: " << x << "\n"; };
captureByValue(); // Вивід: За значенням: 10
captureByRef(); // Вивід: За посиланням: 20
return 0;
}
🔄 Захоплення всіх змінних
C++ дозволяє захоплювати всі локальні змінні з допомогою:
- За значенням:
[=]
- За посиланням:
[&]
Приклад:
#include <iostream>
int main() {
int a = 5, b = 10;
auto captureAllByValue = [=]() { std::cout << "a: " << a << ", b: " << b << "\n"; };
auto captureAllByRef = [&]() { a += 5; b *= 2; std::cout << "a: " << a << ", b: " << b << "\n"; };
captureAllByValue(); // Вивід: a: 5, b: 10
captureAllByRef(); // Вивід: a: 10, b: 20
return 0;
}
🛠️ Захоплення об'єктів у членах класу
У членах класу захоплення this
дозволяє лямбда-виразам доступ до змінних класу.
Приклад:
#include <iostream>
class Counter {
int count;
public:
Counter(int c) : count(c) {}
void increment() {
auto lambda = [this]() { count++; };
lambda();
std::cout << "Count: " << count << "\n";
}
};
int main() {
Counter c(5);
c.increment(); // Вивід: Count: 6
return 0;
}
🧩 Ключова відмінність: Захоплення this
дозволяє лямбда-виразам змінювати або читати члени класу, на відміну від звичайних локальних змінних.
🔍 Приклад: Пошук кратних за допомогою захоплення лямбда-виразом
Давайте покращимо наш приклад з std::count_if
, щоб знайти точні кратні заданого користувачем числа.
Код:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> nums{3, 6, 9, 12, 15, 20};
int multipleOf = 3;
// Лямбда з захопленням
auto isMultiple = [&multipleOf](int x) { return x % multipleOf == 0; };
int count = std::count_if(nums.begin(), nums.end(), isMultiple);
std::cout << "Кількість кратних " << multipleOf << ": " << count << "\n";
return 0;
}
Вивід:
Кількість кратних 3: 5
🚀 Чому лямбда-вирази змінюють правила гри
1.
Вбудовані та лаконічні: Не потрібно окремих функцій.
2. Потужний механізм захоплення: Доступ до змінних без глобального стану.
3. Ідеальні для алгоритмів: Покращують читабельність у функціях STL, таких як std::sort
, std::transform
тощо.
від: Malinda Gamage
Перекладено з: 🚀 Modern C++: Exploring Lambda Expressions in Depth 🔍