C ++

Lambda-udtryk i C ++

Lambda-udtryk i C ++

Hvorfor Lambda Expression?

Overvej følgende udsagn:

    int myInt = 52;

Her er myInt en identifikator, en værdi. 52 er en bogstavelig, en værdi. I dag er det muligt at kode en funktion specielt og placere den i positionen 52. En sådan funktion kaldes et lambda-udtryk. Overvej også følgende korte program:

#omfatte
ved hjælp af namespace std;
int fn (int par)

int svar = par + 3;
returnere svar

int main ()

fn (5);
returnere 0;

I dag er det muligt at kode en funktion specielt og placere den i positionen af ​​argumentet 5, for funktionsopkaldet, fn (5). En sådan funktion kaldes et lambda-udtryk. Lambda-udtrykket (funktionen) i denne position er en værdi.

Enhver bogstavelig undtagen strengen bogstavelig er en værdi. Lambda-udtrykket er et specielt funktionsdesign, der passer til en bogstavelig kode. Det er en anonym (unavngiven) funktion. Denne artikel forklarer det nye C ++ primære udtryk, kaldet lambda-udtrykket. Grundlæggende viden i C ++ er et krav for at forstå denne artikel.

Artikelindhold

  • Illustration af Lambda Expression
  • Dele af Lambda Expression
  • Optager
  • Klassisk Callback Function Scheme med Lambda Expression
  • Den bageste-retur-type
  • Lukning
  • Konklusion

Illustration af Lambda Expression

I det følgende program tildeles en funktion, som er et lambda-udtryk, en variabel:

#omfatte
ved hjælp af namespace std;
auto fn = [] (int param)

int svar = param + 3;
returnere svar
;
int main ()

auto variab = fn (2);
cout << variab << '\n';
returnere 0;

Outputtet er:

    5

Uden for hovedfunktionen () er der variablen, fn. Dens type er automatisk. Auto i denne situation betyder, at den faktiske type, såsom int eller float, bestemmes af den rette operand af tildelingsoperatøren (=). Til højre for opgaveoperatøren er et lambda-udtryk. Et lambda-udtryk er en funktion uden den foregående returtype. Bemærk brugen og placeringen af ​​de firkantede parenteser, []. Funktionen returnerer 5, en int, som bestemmer typen for fn.

I hovedfunktionen () er der udsagnet:

    auto variab = fn (2);

Dette betyder, at fn uden for hoved () ender som identifikator for en funktion. Dens implicitte parametre er dem for lambda-udtrykket. Typen for variab er auto.

Bemærk, at lambda-udtrykket ender med et semikolon, ligesom definitionen af ​​klasse eller struktur, ender med et semikolon.

I det følgende program er en funktion, som er et lambda-udtryk, der returnerer værdien 5, et argument til en anden funktion:

#omfatte
ved hjælp af namespace std;
ugyldigt otherfn (int no1, int (* ptr) (int))

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

int main ()

otherfn (4, [] (int param)

int svar = param + 3;
returnere svar
);
returnere 0;

Outputtet er:

    4 5

Der er to funktioner her, lambda-udtrykket og den andenfn () -funktion. Lambda-udtrykket er det andet argument for den andenfn (), kaldet main (). Bemærk, at lambda-funktionen (udtryk) ikke ender med semikolon i dette opkald, fordi det her er et argument (ikke en enkeltstående funktion).

Lambda-funktionsparameteren i definitionen af ​​den andenfn () -funktion er en markør til en funktion. Markøren har navnet ptr. Navnet, ptr, bruges i definitionen af ​​otherfn () til at kalde lambda-funktionen.

Erklæringen,

    int no2 = (* ptr) (2);

I definitionen otherfn () kalder den lambda-funktionen med et argument på 2. Returværdien af ​​opkaldet "(* ptr) (2)" fra lambda-funktionen tildeles nr. 2.

Ovenstående program viser også, hvordan lambda-funktionen kan bruges i C ++ callback-funktionsskemaet.

Dele af Lambda Expression

Dele af en typisk lambda-funktion er som følger:

    [] ()
  • [] er fangstklausulen. Det kan have genstande.
  • () er til parameterlisten.
  • er til funktionskroppen. Hvis funktionen står alene, skal den ende med et semikolon.

Optager

Lambda-funktionsdefinitionen kan tildeles en variabel eller bruges som argument til et andet funktionsopkald. Definitionen for et sådant funktionsopkald skal have som parameter en markør til en funktion svarende til lambdafunktionsdefinitionen.

Lambda-funktionsdefinitionen er forskellig fra den normale funktionsdefinition. Den kan tildeles en variabel i det globale omfang; denne funktion-tildelt-til-variabel kan også kodes i en anden funktion. Når den er tildelt en global scope-variabel, kan dens krop se andre variabler i den globale scope. Når den tildeles en variabel inde i en normal funktionsdefinition, kan dens krop kun se andre variabler i funktionsomfanget med hjælp af capture-klausulen, [].

Capture-klausulen [], også kendt som lambda-introduceren, tillader variabler, der skal sendes fra det omgivende (funktions) omfang ind i lambda-ekspressionens funktionslegeme. Lambda-ekspressionens funktionslegeme siges at fange variablen, når den modtager objektet. Uden capture-klausulen [] kan en variabel ikke sendes fra det omgivende omfang til lambda-ekspressionens funktionslegeme. Det følgende program illustrerer dette med det vigtigste () funktionsomfang som det omgivende omfang:

#omfatte
ved hjælp af namespace std;
int main ()

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

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

Outputtet er 5. Uden navnet, id, inden i [], ville lambda-udtrykket ikke have set variablen id for hovedfunktionsområdet ().

Optagelse med reference

Ovenstående eksempel på anvendelse af capture-klausulen er capture efter værdi (se detaljer nedenfor). Ved optagelse ved henvisning placeres (lagring) af variablen, f.eks.g., id ovenfor, af det omgivende omfang, stilles til rådighed inde i lambda-funktionskroppen. Så ændring af værdien af ​​variablen inde i lambda-funktionskroppen vil ændre værdien af ​​den samme variabel i det omgivende omfang. Hver variabel, der gentages i capture-klausulen, er forud for ampersand (&) for at opnå dette. Følgende program illustrerer dette:

#omfatte
ved hjælp af namespace std;
int main ()

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

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

Outputtet er:

    6, 3.4, B

Bekræftelse af, at variabelnavne inde i lambda-ekspressionens funktionslegeme er for de samme variabler uden for lambda-udtrykket.

Optagelse efter værdi

Ved optagelse efter værdi stilles en kopi af variabelens placering, af det omgivende omfang til rådighed inde i lambdafunktionslegemet. Selvom variablen inde i lambdafunktionslegemet er en kopi, kan dens værdi ikke ændres inden i kroppen fra nu af. For at opnå optagelse efter værdi går hver variabel, der gentages i capture-klausulen, ikke forud for noget. Følgende program illustrerer dette:

#omfatte
ved hjælp af namespace std;
int main ()

int id = 5; flyde ft = 2.3; char ch = 'A';
auto 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';
returnere 0;

Outputtet er:

5, 2.3, A
6, 3.4, B

Hvis kommentarindikatoren fjernes, kompileres ikke programmet. Compileren udsender en fejlmeddelelse om, at variablerne i funktionskroppens definition af lambda-udtrykket ikke kan ændres. Selvom variablerne ikke kan ændres inden for lambda-funktionen, kan de ændres uden for lambda-funktionen, som ovenstående programs output viser.

Blanding af optagelser

Optagelse med reference og optagelse efter værdi kan blandes, som det følgende program viser:

#omfatte
ved hjælp af namespace std;
int main ()

int id = 5; flyde ft = 2.3; char ch = 'A'; bool bl = sand;
auto fn = [id, ft, & ch, & bl] ()

ch = 'B'; bl = falsk;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
returnere 0;

Outputtet er:

    5, 2.3, B, 0

Når alle er fanget, er de som reference:

Hvis alle variabler, der skal fanges, fanges ved henvisning, er det kun en &, der er tilstrækkelig i fangstklausulen. Følgende program illustrerer dette:

#omfatte
ved hjælp af namespace std;
int main ()

int id = 5; flyde ft = 2.3; char ch = 'A'; bool bl = sand;
auto fn = [&] ()

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

Outputtet er:

6, 3.4, B, 0

Hvis nogle variabler skal fanges med reference og andre efter værdi, repræsenterer en & alle referencer, og resten vil hver ikke blive forud for noget, som det følgende program viser:

ved hjælp af namespace std;
int main ()

int id = 5; flyde ft = 2.3; char ch = 'A'; bool bl = sandt;
auto fn = [&, id, ft] ()

ch = 'B'; bl = falsk;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
returnere 0;

Outputtet er:

5, 2.3, B, 0

Bemærk at & alene (i.e., & ikke efterfulgt af en identifikator) skal være det første tegn i capture-klausulen.

Når alle er fanget, er de efter værdi:

Hvis alle variabler, der skal fanges, skal fanges efter værdi, er bare en = tilstrækkelig i fangstklausulen. Følgende program illustrerer dette:

#omfatte
ved hjælp af namespace std;
int main ()

int id = 5; flyde ft = 2.3; char ch = 'A'; bool bl = sand;
auto fn = [=] ()

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

Outputtet er:

5, 2.3, A, 1

Bemærk: = er skrivebeskyttet, lige nu.

Hvis nogle variabler skal fanges af værdi og andre som reference, repræsenterer en = alle de skrivebeskyttede kopierede variabler, og resten har hver &, som det følgende program viser:

#omfatte
ved hjælp af namespace std;
int main ()

int id = 5; flyde ft = 2.3; char ch = 'A'; bool bl = sand;
auto fn = [=, & ch, & bl] ()

ch = 'B'; bl = falsk;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
returnere 0;

Outputtet er:

5, 2.3, B, 0

Bemærk, at = alene skal være det første tegn i capture-klausulen.

Klassisk Callback Function Scheme med Lambda Expression

Følgende program viser, hvordan et klassisk tilbagekaldsfunktionsskema kan udføres med lambda-udtrykket:

#omfatte
ved hjælp af namespace std;
char * output;
auto cba = [] (char out [])

output = ud;
;
void principalFunc (char input [], void (* pt) (char []))

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

ugyldigt fn ()

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

int main ()

char input [] = "til tilbagekaldsfunktion";
principalFunc (input, cba);
fn ();
cout<returnere 0;

Outputtet er:

til hovedfunktion
Nu
til tilbagekaldsfunktion

Husk at når en lambda-ekspressionsdefinition er tildelt en variabel i det globale omfang, kan dens funktionslegeme se globale variabler uden at anvende capture-klausulen.

Den bageste-retur-type

Returtypen for et lambda-udtryk er auto, hvilket betyder, at kompilatoren bestemmer returtypen ud fra returudtrykket (hvis det findes). Hvis programmøren virkelig vil angive returtypen, gør han det som i følgende program:

#omfatte
ved hjælp af namespace std;
auto fn = [] (int param) -> int

int svar = param + 3;
returnere svar
;
int main ()

auto variab = fn (2);
cout << variab << '\n';
returnere 0;

Outputtet er 5. Efter parameterlisten indtastes piloperatoren. Dette efterfølges af returtypen (int i dette tilfælde).

Lukning

Overvej følgende kodesegment:

struct Cla

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

Her er Cla navnet på struct-klassen.  Obj1 og obj2 er to objekter, der instantieres fra strukturklassen. Lambda-udtryk er ens i implementeringen. Lambda-funktionens definition er en slags klasse. Når lambda-funktionen kaldes (påkaldt), instantieres et objekt ud fra dets definition. Dette objekt kaldes en lukning. Det er lukningen, der udfører det arbejde, som lambda forventes at udføre.

Kodning af lambda-udtrykket som strukturen ovenfor vil dog have obj1 og obj2 erstattet af de tilsvarende parametres argumenter. Følgende program illustrerer dette:

#omfatte
ved hjælp af namespace std;
auto fn = [] (int param1, int param2)

int svar = param1 + param2;
returnere svar
(2, 3);
int main ()

auto var = fn;
cout << var << '\n';
returnere 0;

Outputtet er 5. Argumenterne er 2 og 3 i parentes. Bemærk, at lambda-ekspressionsfunktionsopkaldet, fn, ikke tager noget argument, da argumenterne allerede er kodet i slutningen af ​​definitionen af ​​lambda-funktionen.

Konklusion

Lambda-udtrykket er en anonym funktion. Det er i to dele: klasse og objekt. Dens definition er en slags klasse. Når udtrykket kaldes, dannes et objekt ud fra definitionen. Dette objekt kaldes en lukning. Det er lukningen, der udfører det arbejde, som lambda forventes at udføre.

For at lambda-udtrykket kan modtage en variabel fra et ydre funktionsomfang, har det brug for en ikke-tom fangstklausul i sin funktionslegeme.

Mus Remap dine museknapper forskelligt til anden software med X-Mouse Button Control
Remap dine museknapper forskelligt til anden software med X-Mouse Button Control
Måske har du brug for et værktøj, der kan ændre din muses kontrol med hver applikation, du bruger. Hvis dette er tilfældet, kan du prøve en applikatio...
Mus Microsoft Sculpt Touch Wireless Mouse Review
Microsoft Sculpt Touch Wireless Mouse Review
Jeg har for nylig læst om Microsoft Sculpt Touch trådløs mus og besluttede at købe den. Efter at have brugt det et stykke tid besluttede jeg at dele m...
Mus AppyMouse pegefelt på skærmen og musemarkør til Windows-tablets
AppyMouse pegefelt på skærmen og musemarkør til Windows-tablets
Tabletbrugere savner ofte musemarkøren, især når de er vante til at bruge bærbare computere. Touchscreen-smartphones og tablets har mange fordele, og ...