lambda function

Üdvözlöm, Ön a lambda function szó jelentését keresi. A DICTIOUS-ban nem csak a lambda function szó összes szótári jelentését megtalálod, hanem megismerheted az etimológiáját, a jellemzőit és azt is, hogyan kell a lambda function szót egyes és többes számban mondani. Minden, amit a lambda function szóról tudni kell, itt található. A lambda function szó meghatározása segít abban, hogy pontosabban és helyesebben fogalmazz, amikor beszélsz vagy írsz. Alambda function és más szavak definíciójának ismerete gazdagítja a szókincsedet, és több és jobb nyelvi forráshoz juttat.

Főnév

lambda function (tsz. lambda functions)

  1. (informatika) A lambda függvények vagy lambda kifejezések a C++11 standardban jelentek meg, és a nyelv egyik legnagyobb újítása volt az utóbbi években. A lambda lehetővé teszi, hogy névtelen, inline definiált függvényeket hozzunk létre, amelyeket azonnal használhatunk, vagy akár továbbadhatunk más függvényeknek.

Egyszerűbben fogalmazva: a lambda egy olyan függvény, amit nem kell külön névvel ellátni, hanem közvetlenül a kód helyén definiálunk és használunk.

Miért hasznosak a lambda függvények?

  • Egyszerűsítik a kódot: Nem kell külön függvényt írni minden apró művelethez.
  • Kényelmesebbek a callback-ekhez: Például STL algoritmusokhoz, eseménykezeléshez.
  • Zárják (capture-elik) a környező változókat: Így a lambda függvény hozzáfér a környező scope-ban lévő változókhoz, akár másolva, akár referencia szerint.

Lambda függvény alap szintaxisa

A legegyszerűbb lambda így néz ki:

 ( parameters ) -> return_type {
    // function body
};

Mindegyik elem magyarázata:

  • — a lambda „fogási lista” (capture list), azaz mely külső változókat kötünk be.
  • ( parameters ) — a lambda bemeneti paraméterei (lehetnek üresek is).
  • -> return_type — opcionális, megadható a visszatérési típus, ha a fordító nem tudná egyértelműen.
  • { ... } — maga a függvény törzse.

Példa 1: Egyszerű lambda függvény

auto hello = () {
    std::cout << "Hello, lambda!" << std::endl;
};

hello(); // Meghívás

Itt a hello egy névtelen függvény, amit a változóhoz rendelünk, majd meghívunk.

A capture list jelentése

A capture lista adja meg, hogy a lambda milyen külső változókat használhat a környezetből, és hogyan (másolat vagy referencia). Lehetőségek:

  • — semmilyen külső változó nem kerül be.
  • — minden külső változó másolatként bekerül.
  • — minden külső változó referencia szerint bekerül.
  • x változót másolatként, y változót referencia szerint kötünk be.
  • this — a lambda belsejében az aktuális osztályobjektum pointere érhető el.

Példa 2: Capture lista használata

int a = 10;
int b = 20;

auto sum_by_value = () {
    return a + b; // másolatban használja a és b értékét
};

auto sum_by_ref = () {
    return a + b; // referencia szerint használja a és b-t
};

std::cout << sum_by_value() << std::endl; // 30
std::cout << sum_by_ref() << std::endl;   // 30

a = 15;
b = 25;

std::cout << sum_by_value() << std::endl; // 30 (mert másolat)
std::cout << sum_by_ref() << std::endl;   // 40 (mert referencia)

Paraméterek és visszatérési típus

A lambda paraméterei pontosan úgy működnek, mint egy normál függvénynél.

A visszatérési típus megadható explicit módon az -> szintaxissal, vagy implicit, ha a fordító ki tudja következtetni.

Példa 3: Paraméterezett lambda

auto add = (int x, int y) -> int {
    return x + y;
};

std::cout << add(3, 4) << std::endl; // 7

Példa 4: Implicit visszatérési típus

Ha a visszatérési típus egyszerű, elhagyható:

auto multiply = (int x, int y) {
    return x * y; // a fordító int-nek veszi
};

std::cout << multiply(5, 6) << std::endl; // 30

Példa 5: Több utasításos lambda

Ha több utasítást akarunk végrehajtani:

auto greet = (std::string name) {
    std::cout << "Hello, " << name << "!" << std::endl;
};

greet("Dániel");

A lambda mint függvényobjektum (funktor)

A lambda nem sima függvény, hanem egy névtelen osztály egy példánya, amely operator()-t definiál.

Ezért:

  • Lambda típusának nincs konkrét neve, mindig auto-val kell tárolni.
  • Lambda átküldhető olyan helyekre, ahol függvényobjektumot várnak (pl. STL algoritmusok).

STL és lambda függvények

A lambda kifejezések az STL algoritmusokkal nagyon hasznosak.

Példa 6: Rendezés lambda-val

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {3, 1, 4, 1, 5, 9};

    std::sort(v.begin(), v.end(), (int a, int b) {
        return a > b; // csökkenő sorrend
    });

    for (int n : v) {
        std::cout << n << " ";
    }
    std::cout << std::endl;

    return 0;
}

Ez a példa lambda-t használ az egyéni rendezési feltételhez.

Példa 7: Szűrés és feldolgozás

std::vector<int> numbers = {1,2,3,4,5,6,7,8,9,10};
int count_even = 0;

std::for_each(numbers.begin(), numbers.end(), (int x){
    if (x % 2 == 0) {
        ++count_even;
    }
});

std::cout << "Páros számok száma: " << count_even << std::endl;

Mutable lambda

Alapértelmezés szerint, ha a capture másolat (), akkor a lambda testén belül a captured változók nem módosíthatók, mert implicit const a operator().

Ha módosítani szeretnénk a capture-ölt másolatokat, használhatjuk a mutable kulcsszót.

Példa 8: Mutable lambda

int x = 10;

auto f = () mutable {
    x += 5;
    std::cout << "Lambda belsejében x: " << x << std::endl;
};

f(); // kiírja: 15
std::cout << "Külső x: " << x << std::endl; // kiírja: 10 (külső változó nem változik)

A mutable lehetővé teszi, hogy a lambda a captured változó másolatát módosítsa, de nem változtatja meg a külső változót.

Visszatérés lambda függvényként (function returning lambda)

Lambdát visszaadó függvényt is írhatunk.

auto make_adder(int n) {
    return (int x) {
        return x + n;
    };
}

int main() {
    auto add5 = make_adder(5);
    std::cout << add5(10) << std::endl; // 15
}

Típusjegyzék és std::function

Ha lambdát szeretnénk például eltárolni olyan változóban, ami kompatibilis bármilyen hasonló függvénnyel, használhatjuk az std::function-t.

#include <functional>

std::function<int(int,int)> func = (int a, int b) {
    return a + b;
};

std::cout << func(3,4) << std::endl; // 7

Az std::function típus viszont lassabb lehet, mert dinamikus diszpatchet (virtuális függvénytábla hívást) használ.

Capture-ök speciális esetek

  • this capture:

Osztályon belül lambda-t írva elérhetjük az objektum tagjait így:

class MyClass {
    int val = 42;
public:
    void foo() {
        auto lam = () {
            std::cout << val << std::endl;
        };
        lam();
    }
};
  • Capture referencia szerint csak egy változóra:
int a = 10;
auto f = () { a += 5; };
f();
std::cout << a << std::endl; // 15

Több soros, komplex lambdák

Lambda-n belül bármennyi sor lehet:

auto complex = (int x) {
    if (x > 0) {
        std::cout << "Pozitív" << std::endl;
    } else {
        std::cout << "Nem pozitív" << std::endl;
    }
};

Lambda a ciklusokban

Fontos, hogy ha cikluson belül hozunk létre lambdákat, akkor a capture-nek meg kell felelnie annak, amit elvárunk. Például:

std::vector<std::function<void()>> funcs;

for (int i = 0; i < 3; ++i) {
    funcs.push_back(() { std::cout << i << std::endl; });
}

for (auto& f : funcs) {
    f(); // 0 1 2 kiíródik
}

Ha nem capture-eljük i-t értékként, hanem referenciaként, a lambda mindhárom esetben ugyanazt a i változót nézné, ami a ciklus után 3 lesz, tehát mindhárom lambda 3-at írna ki.

Lambda összefoglaló – előnyök és hátrányok

Előnyök:

  • Egyszerű és tömör függvények helyben.
  • Könnyű használat STL algoritmusokkal.
  • Capture segítségével könnyen hozzáférnek a külső környezethez.
  • Funkcionális programozási elemek bevezetése C++-ba.

Hátrányok:

  • Típusuk nem névvel rendelkező, csak auto vagy std::function használható.
  • Ha capture referencia szerint, vigyázni kell az élettartamra.
  • std::function használata lassabb lehet.

Összefoglalás

  • A lambda egy névtelen függvény, amit inline definiálunk.
  • Capture listában megadjuk, mely környező változókat használ a lambda.
  • STL algoritmusokban és callback-ekben nagyon praktikusak.
  • Támogatják a paramétereket és visszatérési típust.
  • mutable kulcsszó lehetővé teszi a másolatként capture-ölt változók módosítását.
  • A lambda típusa névtelen, ezért auto vagy std::function kell a tárolásához.