C ++

Lambda izrazi v jeziku C ++

Lambda izrazi v jeziku C ++

Zakaj Lambda Expression?

Upoštevajte naslednjo izjavo:

    int myInt = 52;

Tu je myInt identifikator, vrednost. 52 je dobesedno, prva vrednost. Danes je mogoče funkcijo posebej kodirati in jo postaviti v položaj 52. Takšni funkciji pravimo lambda izraz. Upoštevajte tudi naslednji kratek program:

#include
uporaba imenskega prostora std;
int fn (int par)

int odgovor = par + 3;
povratni odgovor;

int main ()

fn (5);
vrnitev 0;

Danes je mogoče funkcijo posebej kodirati in jo postaviti v položaj argumenta 5, klica funkcije, fn (5). Takšni funkciji pravimo lambda izraz. Lambda izraz (funkcija) v tem položaju je prva vrednost.

Katera koli dobesedna črka, razen nizovne, je prva vrednost. Lambda izraz je posebna zasnova funkcije, ki bi se v kodi prilegala kot dobesedno besedilo. Gre za anonimno (neimenovano) funkcijo. Ta članek pojasnjuje novi primarni izraz C ++, imenovan lambda izraz. Osnovno znanje jezika C ++ je pogoj za razumevanje tega članka.

Vsebina članka

  • Prikaz Lambda izražanja
  • Deli Lambda Expression
  • Zajemanje
  • Klasična shema funkcije povratnega klica z Lambda Expression
  • Vrsta zaključnega vrnitve
  • Zaključek
  • Zaključek

Prikaz Lambda izražanja

V naslednjem programu je spremenljivki dodeljena funkcija, ki je lambda izraz:

#include
uporaba imenskega prostora std;
samodejno fn = [] (int param)

int odgovor = param + 3;
povratni odgovor;
;
int main ()

samodejna spremenljivka = fn (2);
cout << variab << '\n';
vrnitev 0;

Rezultat je:

    5

Zunaj glavne () funkcije je spremenljivka fn. Njegova vrsta je samodejna. Samodejno v tej situaciji pomeni, da dejanski tip, na primer int ali float, določa desni operand operaterja dodelitve (=). Na desni strani operaterja dodelitve je lambda izraz. Lambda izraz je funkcija brez predhodnega tipa vrnitve. Upoštevajte uporabo in položaj oglatih oklepajev, []. Funkcija vrne 5, int, ki bo določil vrsto za fn.

V glavni () funkciji je stavek:

    samodejna spremenljivka = fn (2);

To pomeni, da se fn zunaj main () konča kot identifikator funkcije. Njeni implicitni parametri so parametri lambda izraza. Tip za variab je samodejno.

Upoštevajte, da se lambda izraz konča s podpičjem, tako kot definicija razreda ali strukture, s podpičjem.

V naslednjem programu je funkcija, ki je lambda izraz, ki vrne vrednost 5, argument drugi funkciji:

#include
uporaba imenskega prostora std;
void otherfn (int št1, int (* ptr) (int))

int št2 = (* ptr) (2);
cout << no1 << " << no2 << '\n';

int main ()

otherfn (4, [] (int param)

int odgovor = param + 3;
povratni odgovor;
);
vrnitev 0;

Rezultat je:

    4 5

Tu sta dve funkciji, lambda izraz in funkcija otherfn (). Lambda izraz je drugi argument drugefn (), ki se imenuje main (). Upoštevajte, da se lambda funkcija (izraz) v tem klicu ne konča s podpičjem, ker je tu argument (ne samostojna funkcija).

Parameter lambda funkcije v definiciji funkcije otherfn () je kazalec na funkcijo. Kazalec ima ime, ptr. Ime, ptr, se uporablja v definiciji otherfn () za klicanje funkcije lambda.

Izjava,

    int št2 = (* ptr) (2);

V definiciji otherfn () prikliče funkcijo lambda z argumentom 2. Vrnjena vrednost klica, "(* ptr) (2)" iz funkcije lambda, je dodeljena no2.

Zgornji program prikazuje tudi, kako lahko funkcijo lambda uporabljamo v shemi funkcij povratnega klica C ++.

Deli Lambda Expression

Deli tipične lambda funkcije so naslednji:

    [] ()
  • [] je klavzula za zajem. Lahko ima predmete.
  • () je za seznam parametrov.
  • je za telo funkcije. Če funkcija stoji samostojno, se mora končati s podpičjem.

Zajemanje

Definicijo lambda funkcije lahko dodelite spremenljivki ali uporabite kot argument za drug klic funkcije. Definicija za tak klic funkcije mora imeti kot parameter kazalec na funkcijo, ki ustreza definiciji lambda funkcije.

Definicija lambda funkcije se razlikuje od običajne definicije funkcije. Lahko se dodeli spremenljivki v globalnem obsegu; ta funkcija, dodeljena spremenljivki, se lahko kodira tudi znotraj druge funkcije. Ko je telo dodeljeno spremenljivki globalnega obsega, lahko vidi druge spremenljivke v globalnem obsegu. Ko je telo dodeljeno spremenljivki znotraj običajne definicije funkcije, lahko vidi druge spremenljivke v obsegu funkcije samo s pomočjo klavzule za zajem, [].

Klavzula za zajemanje [], znana tudi kot lambda-uvodnik, omogoča pošiljanje spremenljivk iz okolice (funkcije) v telo funkcije lambda izraza. Telo funkcije lambda izraza naj bi zajemalo spremenljivko, ko prejme objekt. Brez klavzule zajemanja [] spremenljivke ni mogoče poslati iz okoliškega obsega v telo funkcije lambda izraza. Naslednji program to ponazarja z obsegom funkcije main () kot okoliškim obsegom:

#include
uporaba imenskega prostora std;
int main ()

int id = 5;
samodejno fn = [id] ()

cout << id << '\n';
;
fn ();
vrnitev 0;

Izhod je 5. Brez imena, id znotraj [] lambda izraz ne bi videl spremenljivke id področja funkcije main ().

Zajem z referenco

Zgornji primer uporabe stavka zajemanje je zajem po vrednosti (glej podrobnosti spodaj). Pri zajemanju s sklicem je lokacija (shranjevanje) spremenljivke, npr.g., ID zgoraj, okoliškega obsega, je na voljo znotraj telesa lambda funkcije. Torej, sprememba vrednosti spremenljivke v telesu funkcije lambda bo spremenila vrednost iste spremenljivke v okoliškem obsegu. Za dosego tega pred vsako spremenljivko, ki se ponovi v stavku zajemanja, stoji znak & (&). Naslednji program to ponazarja:

#include
uporaba imenskega prostora std;
int main ()

int id = 5; float ft = 2.3; char ch = 'A';
samodejno fn = [& id, & ft, & ch] ()

id = 6; ft = 3.4; ch = 'B';
;
fn ();
cout << id << ", " <<  ft << ", " <<  ch << '\n';
vrnitev 0;

Rezultat je:

    6, 3.4, B

Potrditev, da so imena spremenljivk znotraj telesa funkcije lambda izraza enaka spremenljivkam zunaj lambda izraza.

Zajemanje po vrednosti

Pri zajemanju po vrednosti je v telesu funkcije lambda na voljo kopija lokacije spremenljivke in okoliškega obsega. Čeprav je spremenljivka v telesu lambda funkcije kopija, njene vrednosti od zdaj ni mogoče spremeniti znotraj telesa. Da bi dosegli zajem po vrednosti, pred vsako spremenljivko, ponovljeno v stavku zajemanja, ne stoji nič. Naslednji program to ponazarja:

#include
uporaba imenskega prostora std;
int main ()

int id = 5; float ft = 2.3; char ch = 'A';
samodejno fn = [id, ft, 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';
vrnitev 0;

Rezultat je:

5, 2.3, A
6, 3.4, B

Če indikator komentarja odstranite, se program ne bo prevedel. Prevajalnik bo izdal sporočilo o napaki, da spremenljivk v definiciji lambda izraza v funkcijskem telesu ni mogoče spremeniti. Čeprav spremenljivk ni mogoče spremeniti znotraj lambda funkcije, jih je mogoče spremeniti zunaj lambda funkcije, kot kaže zgornji izhod programa.

Mešanje posnetkov

Zajem z referenco in zajem z vrednostjo je mogoče mešati, kot kaže naslednji program:

#include
uporaba imenskega prostora std;
int main ()

int id = 5; float ft = 2.3; char ch = 'A'; bool bl = res;
samodejno fn = [id, ft, & ch, & bl] ()

ch = 'B'; bl = napačno;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
vrnitev 0;

Rezultat je:

    5, 2.3, B, 0

Ko so vsi zajeti, so po sklicu:

Če so vse spremenljivke, ki jih je treba zajeti, zajete s sklicem, bo v stavku za zajemanje zadostovala samo ena &. Naslednji program to ponazarja:

#include
uporaba imenskega prostora std;
int main ()

int id = 5; float ft = 2.3; char ch = 'A'; bool bl = res;
samodejno fn = [&] ()

id = 6; ft = 3.4; ch = 'B'; bl = napačno;
;
fn ();
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
vrnitev 0;

Rezultat je:

6, 3.4, B, 0

Če je treba nekatere spremenljivke zajeti s sklicem, druge pa z vrednostjo, potem bo ena & predstavljala vse sklice, pred ostalimi pa ne bo nič, kot kaže naslednji program:

uporaba imenskega prostora std;
int main ()

int id = 5; float ft = 2.3; char ch = 'A'; bool bl = res;
samodejno fn = [&, id, ft] ()

ch = 'B'; bl = napačno;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
vrnitev 0;

Rezultat je:

5, 2.3, B, 0

Upoštevajte, da & sam (i.e., & ne sledi mu identifikator) mora biti prvi znak v stavku za zajemanje.

Ko so vsi zajeti, so po vrednosti:

Če je treba vse spremenljivke, ki jih je treba zajeti, zajeti po vrednosti, potem bo v klavzuli za zajemanje zadostovalo samo eno =. Naslednji program to ponazarja:

#include
uporaba imenskega prostora std;
int main ()

int id = 5; float ft = 2.3; char ch = 'A'; bool bl = res;
samodejno fn = [=] ()

cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
vrnitev 0;

Rezultat je:

5, 2.3, A, 1

Opomba: = je od zdaj samo za branje.

Če je treba nekatere spremenljivke zajeti z vrednostjo, druge pa s sklicem, potem bo ena = predstavljala vse samo za branje kopirane spremenljivke, ostale pa bodo imele &, kot kaže naslednji program:

#include
uporaba imenskega prostora std;
int main ()

int id = 5; float ft = 2.3; char ch = 'A'; bool bl = res;
samodejno fn = [=, & ch, & bl] ()

ch = 'B'; bl = napačno;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
vrnitev 0;

Rezultat je:

5, 2.3, B, 0

Upoštevajte, da mora biti = same prvi znak v stavku za zajem.

Klasična shema funkcije povratnega klica z Lambda Expression

Naslednji program prikazuje, kako lahko izvedemo klasično shemo funkcij povratnega klica z lambda izrazom:

#include
uporaba imenskega prostora std;
char * izhod;
samodejno cba = [] (črka ven [])

izhod = ven;
;
void principalFunc (vnos znaka [], void (* pt) (char []))

(* pt) (vnos);
cout<<"for principal function"<<'\n';

void fn ()

cout<<"Now"<<'\n';

int main ()

char input [] = "za funkcijo povratnega klica";
principalFunc (vnos, cba);
fn ();
cout<vrnitev 0;

Rezultat je:

za glavno funkcijo
Zdaj
za funkcijo povratnega klica

Spomnimo se, da ko je definicija lambda izraza dodeljena spremenljivki v globalnem obsegu, lahko njeno funkcijsko telo vidi globalne spremenljivke brez uporabe klavzule za zajem.

Vrsta zaključnega vrnitve

Vrnitev tipa lambda izraza je samodejna, kar pomeni, da prevajalnik določi vrsto vrnitve iz izraza return (če je prisoten). Če programer resnično želi navesti vrsto vrnitve, bo to storil kot v naslednjem programu:

#include
uporaba imenskega prostora std;
samodejno fn = [] (int param) -> int

int odgovor = param + 3;
povratni odgovor;
;
int main ()

samodejna spremenljivka = fn (2);
cout << variab << '\n';
vrnitev 0;

Izhod je 5. Po seznamu parametrov se vnese operator puščice. Temu sledi vrsta vrnitve (v tem primeru int).

Zaključek

Upoštevajte naslednji segment kode:

struct Cla

int id = 5;
char ch = 'a';
obj1, obj2;

Tu je Cla ime razreda struct.  Obj1 in obj2 sta dva predmeta, ki se bosta ustvarila iz razreda struct. Izraz Lambda je pri izvajanju podoben. Opredelitev lambda funkcije je neke vrste razred. Ko je lambda funkcija poklicana (priklicana), se objekt ustvari iz njegove definicije. Ta predmet se imenuje zaprtje. Zaprtje je tisto, kar pričakuje lambda.

Vendar bo kodiranje lambda izraza, kot je zgornja struktura, obj1 in obj2 nadomeščena z argumentoma ustreznih parametrov. Naslednji program to ponazarja:

#include
uporaba imenskega prostora std;
samodejno fn = [] (int param1, int param2)

int odgovor = param1 + param2;
povratni odgovor;
(2, 3);
int main ()

samodejno var = fn;
cout << var << '\n';
vrnitev 0;

Izhod je 5. Argumenta sta v oklepajih 2 in 3. Upoštevajte, da klic funkcije lambda izraz fn ne sprejme nobenega argumenta, ker so argumenti že kodirani na koncu definicije lambda funkcije.

Zaključek

Izraz lambda je anonimna funkcija. Sestavljen je iz dveh delov: razreda in predmeta. Njegova definicija je nekakšen razred. Ko je izraz poklican, se iz definicije oblikuje predmet. Ta predmet se imenuje zaprtje. Zaprtje je tisto, kar pričakuje lambda.

Da lambda izraz prejme spremenljivko iz zunanjega obsega funkcije, potrebuje neprazno klavzulo za zajem v svoje telo funkcije.

Najboljše igre z ročnim sledenjem
Oculus Quest je pred kratkim predstavil odlično idejo ročnega sledenja brez krmilnikov. Z vedno večjim številom iger in dejavnosti, ki izvajajo podpor...
Kako prikazati prekrivanje zaslonskega menija v celozaslonskih aplikacijah in igrah za Linux
Igranje celozaslonskih iger ali uporaba aplikacij v celozaslonskem načinu brez motenj vam lahko odreže ustrezne sistemske informacije, ki so vidne na ...
Top 5 kartic za zajemanje iger
Vsi smo v YouTubu videli in oboževali pretakanje iger. PewDiePie, Jakesepticye in Markiplier so le nekateri izmed najboljših igralcev, ki so zaslužili...