anonymous function

Üdvözlöm, Ön a anonymous function szó jelentését keresi. A DICTIOUS-ban nem csak a anonymous 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 anonymous function szót egyes és többes számban mondani. Minden, amit a anonymous function szóról tudni kell, itt található. A anonymous function szó meghatározása segít abban, hogy pontosabban és helyesebben fogalmazz, amikor beszélsz vagy írsz. Aanonymous 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

anonymous function (tsz. anonymous functions)

  1. (informatika) Az anonim függvény olyan függvény, amelynek nincs neve, és általában rövid, egyszeri használatra készült. A C++11 bevezetésével a nyelv támogatja az ún. lambda kifejezéseket, amelyek pontosan ezt a célt szolgálják: név nélküli függvények létrehozását.

A lambda kifejezések lehetővé teszik, hogy egy függvényt inline (helyben) definiáljunk, gyakran helyi változókkal vagy paraméterekkel együtt, és átadjuk például algoritmusoknak vagy eseménykezelőknek. Ez nagyban javítja a kód tömörségét, olvashatóságát, és rugalmasságát.



Miért hasznosak az anonim függvények?

  • Nem kell külön függvény nevet megadni, mert csak egyszer használjuk.
  • Közvetlenül definiálhatunk viselkedést ott, ahol szükség van rá (például std::sort-ban vagy std::for_each-ben).
  • Képesek környezeti változókat „elkapni” (capture), azaz hozzáférni az őket körülvevő kódrészlet változóihoz.
  • Könnyebb kezelni callback-eket vagy eseményeket.



Lambda szintaxis C++-ban

A lambda kifejezés általános formája:

(parameters) -> return_type {
    // függvény törzse
}
  • capture: megadja, hogy milyen környezeti változókat szeretnénk elérni a lambda-n belül (lásd később).
  • parameters: a függvény paraméterei, hasonlóan a normál függvényekhez.
  • return_type: opcionális, ha nem adjuk meg, a fordító megpróbálja kikövetkeztetni.
  • törzs: a függvény logikája.



Egyszerű példa

#include <iostream>

int main() {
    auto osszeg = (int a, int b) {
        return a + b;
    };

    std::cout << osszeg(5, 3) << std::endl; // 8
    return 0;
}

Itt az osszeg egy változó, amely egy lambda függvényt tárol. Ez a lambda két egész számot vár és visszaadja az összegüket.



A capture lista

A lambda kifejezés egyik legfontosabb része a capture lista. Ez határozza meg, hogy a lambda milyen külső változókat használhat. A capture lista szögletes zárójelek között van: .

Capture módok

  1. Üres capture:
  • Nem használ semmilyen külső változót.
  1. Érték szerinti capture:
  • A változókat értékként másolja be (másolat készül), így a lambda-n belül ezek a változók nem módosíthatók kívülről és a lambda módosításai nem látszanak kívül.
  1. Referenciával capture:
  • Referenciaként „fogja el” a változókat, így a lambda-ban végzett módosítások hatnak a külső változókra.
  1. Automatikus capture mind érték szerint vagy mind referenciával
  • : az összes használt külső változót értékként fogja el.
  • : az összes használt külső változót referenciaként fogja el.



Példák capture-re

#include <iostream>

int main() {
    int x = 10;
    int y = 20;

    auto lambda1 = () {
        std::cout << "x + y = " << x + y << std::endl;
    };
    lambda1(); // 30

    auto lambda2 = () {
        x += 5;
        y += 10;
        std::cout << "Modified: x = " << x << ", y = " << y << std::endl;
    };
    lambda2(); // Modified: x = 15, y = 30

    std::cout << "Outside: x = " << x << ", y = " << y << std::endl;
    // Outside: x = 15, y = 30

    return 0;
}

Return típus megadása

Ha a return típus nem egyértelmű vagy összetettebb, megadhatjuk explicit módon:

auto f = (int a, int b) -> double {
    return (double)(a + b) / 2;
};

Lambda mint függvényparaméter

A lambda kifejezéseket gyakran használjuk STL algoritmusoknál, például a std::sort-nál vagy std::for_each-nél.

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

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

    // Rendezés csökkenő sorrendbe lambda segítségével
    std::sort(szamok.begin(), szamok.end(), (int a, int b) {
        return a > b;
    });

    for (auto szam : szamok) {
        std::cout << szam << " ";
    }
    std::cout << std::endl;

    return 0;
}

Működés közben: lambda változók eltárolása

A lambda kifejezéseket változókba menthetjük az auto kulcsszóval:

auto f = (int x) { return x * x; };
std::cout << f(4); // 16

Mutable lambdák

Alapból, ha egy lambda érték szerint capture-öl egy változót, akkor a lambda nem módosíthatja a captured változó másolatát, mert a lambda operator()-ja const.

Ha szeretnénk, hogy a lambda módosíthassa a captured változók másolatát, akkor használjuk a mutable kulcsszót:

int x = 5;
auto f = () mutable {
    x += 10;
    std::cout << x << std::endl; // 15
};
f();
std::cout << x << std::endl; // 5, mert eredeti x nem változott

Lambda visszatérési érték nélküli függvényként (void)

Nem minden lambda kell, hogy visszatérjen értéket. Lehetnek void típusúak is:

auto kiir = (const std::string& nev) {
    std::cout << "Szia, " << nev << "!" << std::endl;
};
kiir("Dani");

Komplexebb példák

Számoljuk meg egy tömbben azokat az elemeket, amelyek nagyobbak egy adott értéknél:

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

int main() {
    std::vector<int> szamok = {1, 5, 8, 3, 7, 10};
    int hatar = 5;

    int szamlalo = std::count_if(szamok.begin(), szamok.end(), (int x) {
        return x > hatar;
    });

    std::cout << "Nagyobbak, mint " << hatar << ": " << szamlalo << std::endl;

    return 0;
}

Lambda és standard függvény típus (std::function)

Ha szükség van arra, hogy egy lambda változóként vagy paraméterként olyan függvényt tartalmazzon, aminek a típusa nem ismert (például bonyolult capture lista miatt), használhatjuk a std::function típust:

#include <functional>

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

Ez viszont kicsit lassabb, mert a std::function egy absztrakt tároló.



Lambda kifejezések előtti megoldások C++-ban

Korábban, a C++11 előtt, az ilyen inline, név nélküli függvények megoldására gyakran használtak:

  • Funktor osztályokat (operator() túlterhelve)
  • Funkció pointereket, de ezek nem támogatták a változók „elkapását”

Példa funktorra:

struct Osszeg {
    int operator()(int a, int b) {
        return a + b;
    }
};

Osszeg osszeg;
std::cout << osszeg(3, 4);

Összefoglalás

  • Az anonim függvények C++-ban lambda kifejezések néven ismertek.
  • Lambda szintaxis: (parameters) -> return_type { body }.
  • Képesek környezeti változókat értékként vagy referenciaként „elkapni”.
  • Használjuk őket helyi, rövid függvényekhez, különösen STL algoritmusokban.
  • A mutable kulcsszóval módosíthatjuk a capture-ölt változók másolatát.
  • std::function-nel tárolhatjuk lambda típusú változókat, ha szükséges.
  • Lambda kifejezések jelentősen javítják a kód olvashatóságát és karbantarthatóságát a modern C++-ban.