🚀 Сучасний C++: Глибоке занурення у вирази лямбда 🔍

C++ лямбда-вирази — одна з найкрутіших особливостей, введених у C++11, що дозволяє розробникам C++ використовувати можливості функціонального програмування. Вони спрощують код і роблять його більш лаконічним, особливо при роботі з алгоритмами. Давайте детально розглянемо лямбда-вирази, крок за кроком. 💡

pic

🔎 Що таке лямбда-вираз?

Лямбда-вираз — це анонімна функція, визначена безпосередньо в вашому коді.
Лямбда-вирази C++ — одна з найкрутіших особливостей, що були введені в C++11, які приносять можливості функціонального програмування для розробників C++. Вони спрощують код і роблять його більш лаконічним, особливо при роботі з алгоритмами. Давайте детально розглянемо лямбда-вирази, крок за кроком. 💡

pic

🔎 Що таке лямбда-вираз?

Лямбда-вираз — це анонімна функція, визначена безпосередньо у вашому коді.

  • Чому їх використовувати?
    Лямбда-вирази ідеально підходять для короткострокових завдань, таких як кастомне сортування, фільтрація або прості зворотні виклики.

🖋️ Як написати лямбда-вираз

Основний синтаксис лямбда-виразу:

[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 🔍

Leave a Reply

Your email address will not be published. Required fields are marked *