Miks Lambda Expression?
Vaatleme järgmist väidet:
int myInt = 52;Siin on myInt identifikaator, väärtus. 52 on sõna otseses mõttes, prvalue. Täna on võimalik funktsioon spetsiaalselt kodeerida ja panna see 52-le. Sellist funktsiooni nimetatakse lambda avaldiseks. Mõelge ka järgmisele lühiprogrammile:
# kaasatanimeruumi kasutamine std;
int fn (int par)
int vastus = par + 3;
tagasi vastus;
int main ()
fn (5);
tagastama 0;
Täna on võimalik funktsiooni spetsiaalselt kodeerida ja panna funktsiooni kutse fn (5) argumendi positsiooni. Sellist funktsiooni nimetatakse lambda avaldiseks. Selles asendis olev lambda avaldis (funktsioon) on eelväärtus.
Iga literaal, välja arvatud stringi literaal, on prvalue. Lambda avaldis on erifunktsioonide kujundus, mis sobiks koodis sõna otseses mõttes. See on anonüümne (nimetu) funktsioon. Selles artiklis selgitatakse uut C ++ esmast väljendit, mida nimetatakse lambda väljendiks. Selle artikli mõistmiseks on nõutavad algteadmised C ++ keeles.
Artikli sisu
- Lambda ekspressiooni illustratsioon
- Lambda väljenduse osad
- Pildistab
- Klassikaline tagasihelistamisfunktsioonide skeem koos lambda väljendiga
- Tagasi-tagasi-tüüp
- Sulgemine
- Järeldus
Lambda ekspressiooni illustratsioon
Järgmises programmis määratakse muutujale funktsioon, mis on lambda avaldis:
# kaasatanimeruumi kasutamine std;
auto fn = [] (int parameeter)
int vastus = param + 3;
tagasi vastus;
;
int main ()
automaatne muutuja = fn (2);
cout << variab << '\n';
tagastama 0;
Väljund on:
5Funktsiooni main () kõrval on muutuja fn. Selle tüüp on automaatne. Automaatne tähendab antud olukorras seda, et tegeliku tüübi, näiteks int või float, määrab määramise operaatori õige operand (=). Omistusoperaatori paremal on lambda avaldis. Lambda avaldis on funktsioon ilma eelneva tagasitüübita. Pange tähele nurksulgude kasutamist ja asukohta, []. Funktsioon tagastab 5, int, mis määrab fn tüübi.
Funktsioonis main () on lause:
automaatne muutuja = fn (2);See tähendab, et fn väljaspool main () on funktsiooni identifikaator. Selle kaudsed parameetrid on lambda ekspressiooni parameetrid. Muutuja tüüp on auto.
Pange tähele, et lambda avaldis lõpeb semikooloniga, täpselt nagu klass või struktuuri määratlus, lõpeb semikooloniga.
Järgmises programmis on funktsioon, mis on lambda avaldis, mis tagastab väärtuse 5, argumendiks teisele funktsioonile:
# kaasatanimeruumi kasutamine std;
void otherfn (int no1, int (* ptr) (int))
int nr2 = (* ptr) (2);
cout << no1 << " << no2 << '\n';
int main ()
muufn (4, [] (int param)
int vastus = param + 3;
tagasi vastus;
);
tagastama 0;
Väljund on:
4 5Siin on kaks funktsiooni, lambda avaldis ja funktsioon otherfn (). Lambda avaldis on teise argumendi otherfn () nimega main (). Pange tähele, et lambda funktsioon (avaldis) ei lõpe selles kõnes semikooloniga, kuna siin on see argument (mitte eraldiseisev funktsioon).
Funktsiooni parameeter lambda funktsiooni otherfn () määratluses on funktsiooni kursor. Kursoril on nimi, ptr. Nime ptr kasutatakse funktsiooni lambda kutsumiseks definitsioonis otherfn ().
Avaldus,
int nr2 = (* ptr) (2);Definitsioonis otherfn () kutsub see lambda funktsiooni argumendiga 2. Kõne tagasiväärtus "(* ptr) (2)" lambda funktsioonist määratakse numbrile2.
Ülalolev programm näitab ka seda, kuidas funktsiooni lambda saab kasutada C ++ tagasihelistamisfunktsioonide skeemis.
Lambda väljenduse osad
Tüüpilise lambda funktsiooni osad on järgmised:
[] ()- [] on püüdmisklausel. Sellel võib olla esemeid.
- () on parameetrite loendi jaoks.
- on funktsiooni kehale. Kui funktsioon seisab üksi, peaks see lõppema semikooloniga.
Pildistab
Funktsiooni lambda määratluse saab määrata muutujale või kasutada argumendina teisele funktsioonikutsele. Sellise funktsioonikõne definitsioonil peaks olema parameetrina funktsiooni kursor, mis vastab funktsiooni lambda määratlusele.
Lambda funktsiooni määratlus erineb tavalise funktsiooni määratlusest. Selle saab määrata muutujale globaalses ulatuses; selle muutujale määratud funktsioonile saab kodeerida ka teise funktsiooni. Kui see on määratud globaalse ulatusega muutujale, näeb selle keha teisi globaalse ulatuse muutujaid. Kui see on määratud muutujale normaalse funktsiooni definitsiooni sees, näeb selle keha funktsiooni ulatuses teisi muutujaid ainult püüdmisklausli abiga, [].
Püüdmisklausel [], tuntud ka kui lambda sissejuhataja, võimaldab muutujaid ümbritsevast (funktsiooni) ulatusest saata lambda avaldise funktsiooni kehasse. Väidetavalt tabab lambda avaldise funktsioon keha muutuja objekti vastuvõtmisel. Ilma püüdmisklauslita [] ei saa muutujat ümbritsevast ulatusest saata lambda avaldise funktsiooni kehasse. Järgmine programm illustreerib seda funktsiooni main () funktsiooni ulatusega ümbritseva ulatusena:
# kaasatanimeruumi kasutamine std;
int main ()
int id = 5;
auto fn = [id] ()
cout << id << '\n';
;
fn ();
tagastama 0;
Väljund on 5. Ilma nime, id, sees [] poleks lambda avaldis näinud funktsiooni main () funktsiooni muutuja id.
Jäädvustamine viite abil
Ülaltoodud näide püüdmisklauslist on väärtuse järgi hõivamine (vt üksikasju allpool). Viite abil hõivamisel muutuja asukoht (salvestusruum), nt.g., Ülal olev ümbritseva ulatusega id on kättesaadav lambda funktsioonikorpuse sees. Niisiis muudab lambda funktsiooni keha muutuja väärtuse muutmine sama muutuja väärtust ümbritsevas ulatuses. Igale püüdmisklauslis korratavale muutujale eelneb selle saavutamiseks tähis (ja). Järgmine programm illustreerib seda:
# kaasatanimeruumi kasutamine std;
int main ()
int id = 5; ujuk ft = 2.3; char ch = 'A';
auto fn = [& id, & ft, & ch] ()
id = 6; ft = 3.4; ch = 'B';
;
fn ();
cout << id << ", " << ft << ", " << ch << '\n';
tagastama 0;
Väljund on:
6, 3.4, BKinnitades, et muutuja nimed lambda avaldise funktsiooni kehas on samade muutujate jaoks väljaspool lambda avaldist.
Väärtuse järgi jäädvustamine
Väärtuse järgi hõivamisel tehakse lambda funktsiooni kehas kättesaadavaks koopia muutuja asukohast ja ümbritsevast ulatusest. Kuigi lambda funktsiooni keha muutuja on koopia, ei saa selle väärtust keha sees praegu muuta. Väärtuse järgi hõivamise saavutamiseks ei eelne igale püüdmisklauslis korratud muutujale midagi. Järgmine programm illustreerib seda:
# kaasatanimeruumi kasutamine std;
int main ()
int id = 5; ujuk ft = 2.3; char ch = 'A';
auto fn = [id, jalad, ch] ()
// id = 6; ft = 3.4; ch = 'B';
cout << id << ", " << ft << ", " << ch << '\n';
;
fn ();
id = 6; ft = 3.4; ch = 'B';
cout << id << ", " << ft << ", " << ch << '\n';
tagastama 0;
Väljund on:
5, 2.3, A6, 3.4, B
Kommentaari indikaatori eemaldamisel programm ei kompileeri. Koostaja väljastab veateate, et funktsiooni keha lambda avaldise definitsioonis olevaid muutujaid ei saa muuta. Kuigi muutujaid ei saa lambda funktsiooni sees muuta, saab neid muuta väljaspool lambda funktsiooni, nagu näitab ülaltoodud programmi väljund.
Salvestuste segamine
Viide ja väärtuse järgi jäädvustamist saab segada, nagu näitab järgmine programm:
# kaasatanimeruumi kasutamine std;
int main ()
int id = 5; ujuk ft = 2.3; char ch = 'A'; bool bl = tõene;
automaatne fn = [id, ft, & ch, & bl] ()
ch = 'B'; bl = vale;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
tagastama 0;
Väljund on:
5, 2.3, B, 0Kui kõik on jäädvustatud, on need viitena:
Kui kõik hõivatavad muutujad on hõivatud viitena, siis piisab haaramisklauslis vaid ühest ja sellest. Järgmine programm illustreerib seda:
# kaasatanimeruumi kasutamine std;
int main ()
int id = 5; ujuk ft = 2.3; char ch = 'A'; bool bl = tõene;
auto fn = [&] ()
id = 6; ft = 3.4; ch = 'B'; bl = vale;
;
fn ();
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
tagastama 0;
Väljund on:
6, 3.4, B, 0Kui mõningaid muutujaid tuleb lüüa viitena ja teisi väärtuse järgi, siis üks ja kõik esindavad kõiki viiteid ning ülejäänutele ei eelne midagi, nagu näitab järgmine programm:
nimeruumi kasutamine std;int main ()
int id = 5; ujuk ft = 2.3; char ch = 'A'; bool bl = tõene;
auto fn = [&, id, jalga] ()
ch = 'B'; bl = vale;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
tagastama 0;
Väljund on:
5, 2.3, B, 0Pange tähele, et & üksi (st.e., & millele järgneb identifikaator) peab olema püüdmisklausli esimene märk.
Kui kõik on hõivatud, on need väärtuse järgi:
Kui kõik hõivatavad muutujad tuleb hõivata väärtuse järgi, siis piisab püüdmisklauslis vaid ühest =. Järgmine programm illustreerib seda:
# kaasatanimeruumi kasutamine std;
int main ()
int id = 5; ujuk ft = 2.3; char ch = 'A'; bool bl = tõene;
automaatne fn = [=] ()
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
tagastama 0;
Väljund on:
5, 2.3, A, 1Märge: = on praegu kirjutuskaitstud.
Kui mõned muutujad tuleb püüda väärtuse ja teised viitega, siis üks = tähistab kõiki kirjutuskaitstud kopeeritud muutujaid ja ülejäänud on mõlemal &, nagu näitab järgmine programm:
# kaasatanimeruumi kasutamine std;
int main ()
int id = 5; ujuk ft = 2.3; char ch = 'A'; bool bl = tõene;
auto fn = [=, & ch, & bl] ()
ch = 'B'; bl = vale;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
tagastama 0;
Väljund on:
5, 2.3, B, 0Pange tähele, et = üksi peab olema püüdmisklausli esimene märk.
Klassikaline tagasihelistamisfunktsioonide skeem koos lambda väljendiga
Järgmine programm näitab, kuidas klassikalist tagasihelistamisfunktsiooni skeemi saab teha lambda avaldisega:
# kaasatanimeruumi kasutamine std;
char * väljund;
automaatne cba = [] (char out [])
väljund = välja;
;
void basicFunc (char sisend [], void (* pt) (char []))
(* pt) (sisend);
cout<<"for principal function"<<'\n';
tühine fn ()
cout<<"Now"<<'\n';
int main ()
char input [] = "tagasihelistamisfunktsiooni jaoks";
peamineFunk (sisend, cba);
fn ();
cout<