Lambda izrazi u C ++

Lambda Expressions C



Zašto Lambda izraz?

Uzmite u obzir sljedeću izjavu:

intmyInt= 52;

Ovdje je myInt identifikator, lvalue. 52 je doslovno, prva vrijednost. Danas je moguće posebno kodirati funkciju i postaviti je u položaj 52. Takva se funkcija naziva lambda izraz. Uzmite u obzir i sljedeći kratki program:







#uključi

koristeći imenski prostorsati;

intfn(intkroz)

{

intodgovor=kroz+ 3;

povratakodgovor;

}


intglavni()

{

fn(5);



povratak 0;

}

Danas je moguće posebno kodirati funkciju i postaviti je u poziciju argumenta 5, poziva funkcije, fn (5). Takva se funkcija naziva lambda izraz. Lambda izraz (funkcija) u tom položaju prva je vrijednost.



Bilo koji literal osim literalnog niza prva je vrijednost. Lambda izraz poseban je dizajn funkcije koji bi se uklopio kao doslovni u kôd. To je anonimna (neimenovana) funkcija. Ovaj članak objašnjava novi primarni C ++ izraz, nazvan lambda izraz. Osnovno znanje C ++ uvjet je za razumijevanje ovog članka.



Sadržaj članka

Ilustracija lambda izraza

U sljedećem programu je varijabli dodijeljena funkcija koja je lambda izraz:





#uključi

koristeći imenski prostorsati;

autofn= [](intStop)

{

intodgovor=Stop+ 3;

povratakodgovor;

};


intglavni()

{

autovarijab=fn(2);

trošak <<varijab<< ' n';


povratak 0;

}

Izlaz je:

5

Izvan funkcije main () nalazi se varijabla, fn. Njegov tip je auto. Auto u ovoj situaciji znači da je stvarni tip, poput int ili float, određen desnim operandom operatora dodjeljivanja (=). S desne strane operatora dodjele nalazi se lambda izraz. Lambda izraz funkcija je bez prethodnog tipa povratka. Obratite pozornost na uporabu i položaj uglatih zagrada, []. Funkcija vraća 5, int, koji će odrediti vrstu za fn.



U funkciji main () postoji naredba:

autovarijab=fn(2);

To znači da fn izvan main () završava kao identifikator funkcije. Njegovi implicitni parametri su oni lambda izraza. Vrsta za variab je auto.

Imajte na umu da lambda izraz završava točkom -zarezom, baš kao i definicija klase ili strukture, završava točkom -zarezom.

U sljedećem programu funkcija, koja je lambda izraz koji vraća vrijednost 5, argument je drugoj funkciji:

#uključi

koristeći imenski prostorsati;

poništitiotherfn(intne 1,int (*ptr)(int))

{

intbr2= (*ptr)(2);

trošak <<br1<< '' <<br2<< ' n';

}


intglavni()

{

otherfn(4,[](intStop)

{

intodgovor=Stop+ 3;

povratakodgovor;

});


povratak 0;
}

Izlaz je:

Četiri pet

Ovdje postoje dvije funkcije, lambda izraz i funkcija otherfn (). Lambda izraz drugi je argument otherfn (), koji se poziva u main (). Imajte na umu da lambda funkcija (izraz) ne završava točkom-zarezom u ovom pozivu jer je ovdje riječ o argumentu (a ne o samostalnoj funkciji).

Parametar lambda funkcije u definiciji funkcije otherfn () je pokazivač na funkciju. Pokazivač ima naziv, ptr. Naziv, ptr, koristi se u definiciji otherfn () za pozivanje lambda funkcije.

Izjava,

intbr2= (*ptr)(2);

U definiciji otherfn (), poziva lambda funkciju s argumentom 2. Povratna vrijednost poziva '(*ptr) (2)' iz lambda funkcije dodjeljuje se no2.

Gornji program također prikazuje kako se lambda funkcija može koristiti u shemi funkcija povratnog poziva C ++.

Dijelovi lambda izraza

Dijelovi tipične lambda funkcije su sljedeći:

[] () {}
  • [] je klauzula hvatanja. Može imati stavke.
  • () služi za popis parametara.
  • {} je za tijelo funkcije. Ako funkcija stoji sama, tada bi trebala završiti točkom -zarezom.

Hvata

Definicija lambda funkcije može se dodijeliti varijabli ili koristiti kao argument drugom pozivu funkcije. Definicija za takav poziv funkcije trebala bi imati kao parametar pokazivač na funkciju, koji odgovara definiciji lambda funkcije.

Definicija lambda funkcije razlikuje se od definicije normalne funkcije. Može se dodijeliti varijabli u globalnom opsegu; ova funkcija dodijeljena varijabli također se može kodirati unutar druge funkcije. Kada je dodijeljena varijabli globalnog opsega, njeno tijelo može vidjeti druge varijable u globalnom opsegu. Kad se dodijeli varijabli unutar normalne definicije funkcije, njezino tijelo može vidjeti druge varijable u opsegu funkcije samo uz pomoć klauzule hvatanja, [].

Klauzula hvatanja [], također poznata kao lambda-uvodnik, omogućuje slanje varijabli iz okolnog (funkcije) opsega u tijelo funkcije lambda izraza. Kaže se da tijelo funkcije lambda izraza hvata varijablu kada primi objekt. Bez klauzule hvatanja [], varijabla se ne može poslati iz okolnog opsega u tijelo funkcije lambda izraza. Sljedeći program to ilustrira s opsegom funkcije main () kao okolnim opsegom:

#uključi

koristeći imenski prostorsati;

intglavni()

{

intiskaznica= 5;


autofn= [iskaznica]()

{

trošak <<iskaznica<< ' n';

};

fn();


povratak 0;

}

Izlaz je 5 . Bez imena, id, unutar [], lambda izraz ne bi vidio varijablu id opsega funkcije main ().

Snimanje prema referenci

Gornji primjer uporabe klauzule hvatanja je hvatanje po vrijednosti (vidi detalje u nastavku). Prilikom hvatanja referencom, mjesto (pohrana) varijable, npr. Gornji id, okolnog opsega, dostupno je unutar tijela lambda funkcije. Dakle, promjenom vrijednosti varijable unutar tijela lambda funkcije promijenit će se vrijednost te iste varijable u okolnom opsegu. Svakoj varijabli ponovljenoj u klauzuli hvatanja prethodi ampersand (&) da bi se to postiglo. Sljedeći program to ilustrira:

#uključi

koristeći imenski prostorsati;

intglavni()

{

intiskaznica= 5; plutatift= 2.3; charCH= 'DO';

autofn= [&iskaznica,&ft,&CH]()

{

iskaznica= 6;ft= 3.4;CH= 'B';

};

fn();

trošak <<iskaznica<< ',' <<ft<< ',' <<CH<< ' n';

povratak 0;

}

Izlaz je:

6, 3.4, B

Potvrda da su nazivi varijabli unutar tijela funkcije lambda izraza za iste varijable izvan lambda izraza.

Snimanje prema vrijednosti

Prilikom bilježenja prema vrijednosti, kopija lokacije varijable, okolnog opsega, dostupna je unutar tijela lambda funkcije. Iako je varijabla unutar tijela lambda funkcije kopija, njezina se vrijednost zasad ne može promijeniti. Kako bi se postiglo hvatanje po vrijednosti, svakoj varijabli ponovljenoj u klauzuli hvatanja ništa ne prethodi. Sljedeći program to ilustrira:

#uključi

koristeći imenski prostorsati;

intglavni()

{

intiskaznica= 5; plutatift= 2.3; charCH= 'DO';

autofn= [id, ft, ch]()

{

// id = 6; ft = 3,4; ch = 'B';

trošak <<iskaznica<< ',' <<ft<< ',' <<CH<< ' n';

};

fn();

iskaznica= 6;ft= 3.4;CH= 'B';

trošak <<iskaznica<< ',' <<ft<< ',' <<CH<< ' n';

povratak 0;

}

Izlaz je:

5, 2.3, A

6, 3.4, B

Ako se ukloni indikator komentara, program se neće sastaviti. Prevoditelj će poslati poruku o pogrešci da se varijable unutar definicije lambda izraza tijela funkcije ne mogu promijeniti. Iako se varijable ne mogu mijenjati unutar lambda funkcije, one se mogu promijeniti izvan lambda funkcije, kao što pokazuje izlaz gore navedenog programa.

Miješanje snimaka

Snimanje prema referenci i hvatanje po vrijednosti može se miješati, kako pokazuje sljedeći program:

#uključi

koristeći imenski prostorsati;

intglavni()

{

intiskaznica= 5; plutatift= 2.3; charCH= 'DO'; boolbl= pravi;


autofn= [id, ft,&CH,&bl]()

{

CH= 'B';bl= lažno;

trošak <<iskaznica<< ',' <<ft<< ',' <<CH<< ',' <<bl<< ' n';

};

fn();


povratak 0;

}

Izlaz je:

5, 2,3, B, 0

Kad se sve uhvati, odnosi se na referencu:

Ako se sve varijable koje se hvataju hvataju referencom, tada će u klauzuli hvatanja biti dovoljna samo jedna &. Sljedeći program to ilustrira:

#uključi

koristeći imenski prostorsati;

intglavni()

{

intiskaznica= 5; plutatift= 2.3; charCH= 'DO'; boolbl= pravi;


autofn= [&]()

{

iskaznica= 6;ft= 3.4;CH= 'B';bl= lažno;

};

fn();

trošak <<iskaznica<< ',' <<ft<< ',' <<CH<< ',' <<bl<< ' n';


povratak 0;

}

Izlaz je:

6, 3,4, B, 0

Ako se neke varijable hvataju referencom, a druge vrijednošću, tada će jedna & predstavljati sve reference, a ostalima neće ništa prethoditi, kako pokazuje sljedeći program:

koristeći imenski prostorsati;

intglavni()

{

intiskaznica= 5; plutatift= 2.3; charCH= 'DO'; boolbl= pravi;


autofn= [&, id, ft]()

{

CH= 'B';bl= lažno;

trošak <<iskaznica<< ',' <<ft<< ',' <<CH<< ',' <<bl<< ' n';

};

fn();


povratak 0;

}

Izlaz je:

5, 2,3, B, 0

Imajte na umu da & sam (tj. & Iza kojeg ne slijedi identifikator) mora biti prvi znak u klauzuli hvatanja.

Kad se sve uhvati, vrijedi prema vrijednosti:

Ako se sve varijable koje se hvataju hvataju po vrijednosti, tada će samo jedna = biti dovoljna u klauzuli hvatanja. Sljedeći program to ilustrira:

#uključi

koristeći imenski prostorsati;

intglavni()
{

intiskaznica= 5; plutatift= 2.3; charCH= 'DO'; boolbl= pravi;


autofn= [=]()

{

trošak <<iskaznica<< ',' <<ft<< ',' <<CH<< ',' <<bl<< ' n';

};

fn();


povratak 0;


}

Izlaz je:

5, 2,3, A, 1

Bilješka : = od sada je samo za čitanje.

Ako se neke varijable hvataju prema vrijednosti, a druge prema referenci, tada će jedna = predstavljati sve kopirane varijable samo za čitanje, a ostale će imati &, kako pokazuje sljedeći program:

#uključi

koristeći imenski prostorsati;

intglavni()

{

intiskaznica= 5; plutatift= 2.3; charCH= 'DO'; boolbl= pravi;


autofn= [=,&CH,&bl]()

{

CH= 'B';bl= lažno;

trošak <<iskaznica<< ',' <<ft<< ',' <<CH<< ',' <<bl<< ' n';

};

fn();


povratak 0;

}

Izlaz je:

5, 2,3, B, 0

Imajte na umu da = sam mora biti prvi znak u klauzuli hvatanja.

Klasična shema funkcija povratnog poziva s lambda izrazom

Sljedeći program prikazuje kako se klasična shema funkcija povratnog poziva može izvesti s lambda izrazom:

#uključi

koristeći imenski prostorsati;

char *izlaz;


autocba= [](charvan[])

{

izlaz=van;

};



poništitimainFunc(charulazni[],poništiti (*za)(char[]))

{

(*za)(ulazni);

trošak<<'za glavnu funkciju'<<' n';

}


poništitifn()

{

trošak<<'Sada'<<' n';

}


intglavni()

{

charulazni[] = 'za funkciju povratnog poziva';

mainFunc(ulaz, cba);

fn();

trošak<<izlaz<<' n';



povratak 0;

}

Izlaz je:

za glavnu funkciju

Sada

za funkciju povratnog poziva

Podsjetimo se da kada je definicija lambda izraza dodijeljena varijabli u globalnom opsegu, njeno tijelo funkcije može vidjeti globalne varijable bez upotrebe klauzule hvatanja.

Trailing-return-type

Vrsta povratka lambda izraza je auto, što znači da prevoditelj određuje vrstu povratka iz povratnog izraza (ako je prisutan). Ako programer zaista želi naznačiti vrstu povratka, učinit će to kao u sljedećem programu:

#uključi

koristeći imenski prostorsati;

autofn= [](intStop) -> int

{

intodgovor=Stop+ 3;

povratakodgovor;

};


intglavni()

{

autovarijab=fn(2);

trošak <<varijab<< ' n';


povratak 0;

}

Izlaz je 5. Nakon popisa parametara upisuje se operator strelice. Nakon toga slijedi povratni tip (int u ovom slučaju).

Zatvaranje

Razmotrite sljedeći segment koda:

structCla

{

intiskaznica= 5;

charCH= 'do';

}obj1, obj2;

Ovdje je Cla naziv klase struct. Obj1 i obj2 dva su objekta koji će se stvoriti iz klase struct. Lambda izraz sličan je u implementaciji. Definicija lambda funkcije svojevrsna je klasa. Kada se lambda funkcija pozove (pozove), objekt se instancira iz njegove definicije. Taj se objekt naziva zatvaranjem. Zatvaranje obavlja posao od kojeg se očekuje da će lambda obaviti posao.

Međutim, kodiranje lambda izraza poput gornje strukture imat će obj1 i obj2 zamijenjene argumentima odgovarajućih parametara. Sljedeći program to ilustrira:

#uključi

koristeći imenski prostorsati;

autofn= [](intparam1,intparam2)

{

intodgovor=param1+param2;

povratakodgovor;

} (2,3);


intglavni()

{

autogdje=fn;

trošak <<gdje<< ' n';


povratak 0;

}

Izlaz je 5. Argumenti su 2 i 3 u zagradama. Imajte na umu da poziv funkcije lambda izraza, fn, ne uzima nikakav argument budući da su argumenti već kodirani na kraju definicije lambda funkcije.

Zaključak

Lambda izraz je anonimna funkcija. Sastoji se od dva dijela: klase i objekta. Njegova je definicija svojevrsna klasa. Kada se izraz pozove, iz definicije se formira objekt. Taj se objekt naziva zatvaranjem. Zatvaranje obavlja posao od kojeg se očekuje da će lambda obaviti posao.

Da bi lambda izraz primio varijablu iz vanjskog opsega funkcije, potrebna mu je neprazna klauzula hvatanja u tijelo funkcije.