#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <numeric>

// Demo: Function returning a lambda
auto makeMultiplier(int factor) {
    // Capture factor by value, return a callable object
    return [factor](int x) { return x * factor; };
}

int main() {
    // 1. Simplest lambda: no capture, auto return type
    auto greet = []() {
        std::cout << "Hello from lambda!" << std::endl;
    };
    greet();

    // 2. With parameters and explicit return type
    auto add = [](int a, int b) -> int {
        return a + b;
    };
    std::cout << "add(3,4) = " << add(3, 4) << std::endl;

    // 3. Capture list: by value and by reference
    int multiplier = 10;
    int copies = 0;

    // Capture multiplier by value, copies by reference
    auto times = [multiplier, &copies](int x) {
        copies++;                 // Modify externally captured variable by reference
        return x * multiplier;
    };
    std::cout << "times(5) = " << times(5) << std::endl;
    std::cout << "copies = " << copies << std::endl; // Output 1

    // 4. Default capture modes: [=] capture all used variables by value, [&] by reference
    int a = 2, b = 3;
    auto sum = [=]() { return a + b; };      // Capture a and b by value
    auto inc = [&]() { a++; b++; };          // Capture a and b by reference
    std::cout << "sum() = " << sum() << std::endl; // 2+3=5
    inc();
    std::cout << "After inc: a=" << a << ", b=" << b << std::endl; // 3,4

    // 5. mutable lambda: allows modifying copies captured by value
    int count = 0;
    auto mutableCounter = [count]() mutable {
        // count here is a copy of external count, mutable allows modification
        return ++count;
    };
    std::cout << "mutableCounter(): " << mutableCounter() << std::endl; // 1
    std::cout << "mutableCounter(): " << mutableCounter() << std::endl; // 2
    std::cout << "External count still = " << count << std::endl;       // 0

    // 6. Using lambda with STL algorithms (most common use case)
    std::vector<int> nums = {5, 2, 8, 1, 9, 3};

    // Sort: descending order
    std::sort(nums.begin(), nums.end(), [](int x, int y) {
        return x > y;
    });
    std::cout << "Sorted descending: ";
    for (int n : nums) std::cout << n << " ";
    std::cout << std::endl;

    // Iterate and modify: double each element
    std::for_each(nums.begin(), nums.end(), [](int &n) {
        n *= 2;
    });
    std::cout << "After doubling: ";
    for (int n : nums) std::cout << n << " ";
    std::cout << std::endl;

    // Conditional count: count elements greater than 5
    int threshold = 5;
    int greaterCount = std::count_if(nums.begin(), nums.end(),
        [threshold](int n) { return n > threshold; });
    std::cout << "Count of elements > " << threshold << ": " << greaterCount << std::endl;

    // 7. Store lambda in std::function (type erasure)
    std::function<int(int, int)> func = [](int x, int y) {
        return x * x + y * y;
    };
    std::cout << "func(3,4) = " << func(3, 4) << std::endl;

    // 8. Return lambda from function
    auto triple = makeMultiplier(3);
    std::cout << "triple(5) = " << triple(5) << std::endl; // 15

    // 9. Generic lambda (C++14): parameters use auto
    auto genericAdd = [](auto a, auto b) { return a + b; };
    std::cout << "genericAdd(3, 5) = " << genericAdd(3, 5) << std::endl;
    std::cout << "genericAdd(2.5, 1.5) = " << genericAdd(2.5, 1.5) << std::endl;
    std::cout << "genericAdd(std::string(\"Hello, \"), \"world!\") = "
              << genericAdd(std::string("Hello, "), "world!") << std::endl;

    // 10. Immediately invoked lambda (often used for complex initialization)
    int x = []() {
        int val = 0;
        // Complex initialization logic...
        for (int i = 1; i <= 10; ++i) val += i;
        return val;
    }();  // Invocation parentheses
    std::cout << "Immediately invoked lambda sum 1..10 = " << x << std::endl;

    return 0;
}

results matching ""

    No results matching ""