anonymous function
Főnév
anonymous function (tsz. anonymous functions)
- (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 vagystd::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:
[capture](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
- Üres capture:
[ ]
- Nem használ semmilyen külső változót.
- Érték szerinti capture:
[x, y]
- 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.
- Referenciával capture:
[&x, &y]
- 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.
- 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 = [x]() 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(), [hatar](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:
[capture](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
mutablekulcsszó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.
- anonymous function - Szótár.net (en-hu)
- anonymous function - Sztaki (en-hu)
- anonymous function - Merriam–Webster
- anonymous function - Cambridge
- anonymous function - WordNet
- anonymous function - Яндекс (en-ru)
- anonymous function - Google (en-hu)
- anonymous function - Wikidata
- anonymous function - Wikipédia (angol)