C ++

Lambda-uttrykk i C ++

Lambda-uttrykk i C ++

Hvorfor Lambda Expression?

Tenk på følgende utsagn:

    int myInt = 52;

Her er myInt en identifikator, en verdi. 52 er en bokstavelig, en verdi. I dag er det mulig å kode en funksjon spesielt og sette den i posisjonen 52. En slik funksjon kalles et lambdauttrykk. Tenk også på følgende korte program:

#inkludere
bruker navneområde std;
int fn (int par)

int svar = par + 3;
returnere svar;

int main ()

fn (5);
retur 0;

I dag er det mulig å kode en funksjon spesielt og sette den i posisjonen til argumentet til 5, for funksjonsanropet, fn (5). En slik funksjon kalles et lambdauttrykk. Lambdauttrykket (funksjonen) i den posisjonen er en verdi.

Enhver bokstavelig, bortsett fra strengen, er en verdi. Lambda-uttrykket er en spesiell funksjonsdesign som passer som en bokstavelig kode. Det er en anonym (ikke navngitt) funksjon. Denne artikkelen forklarer det nye C ++ primære uttrykket, kalt lambdauttrykket. Grunnleggende kunnskap i C ++ er et krav for å forstå denne artikkelen.

Artikkelinnhold

  • Illustrasjon av Lambda Expression
  • Deler av Lambda Expression
  • Fanger
  • Klassisk tilbakeringingsfunksjonsskjema med Lambda-uttrykk
  • Den etterfølgende retur-typen
  • Lukking
  • Konklusjon

Illustrasjon av Lambda Expression

I det følgende programmet er en funksjon, som er et lambdauttrykk, tilordnet en variabel:

#inkludere
bruker navneområde std;
auto fn = [] (int param)

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

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

Utgangen er:

    5

Utenfor hovedfunksjonen () er det variabelen, fn. Dens type er automatisk. Auto i denne situasjonen betyr at den faktiske typen, for eksempel int eller float, bestemmes av den rette operanden til oppdragsoperatøren (=). Til høyre for oppdragsoperatøren er et lambdauttrykk. Et lambdauttrykk er en funksjon uten forrige returtype. Legg merke til bruken og plasseringen av hakeparentesene, []. Funksjonen returnerer 5, en int, som vil bestemme typen for fn.

I hovedfunksjonen () er det utsagnet:

    auto variab = fn (2);

Dette betyr at fn utenfor main () ender som identifikator for en funksjon. Dens implisitte parametere er de for lambda-uttrykket. Typen for variab er auto.

Merk at lambdauttrykket ender med semikolon, akkurat som klasse- eller strukturdefinisjonen, ender med semikolon.

I det følgende programmet er en funksjon, som er et lambdauttrykk som returnerer verdien 5, et argument til en annen funksjon:

#inkludere
bruker navneområde std;
ugyldig 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;
);
retur 0;

Utgangen er:

    4 5

Det er to funksjoner her, lambdauttrykket og den andrefn () -funksjonen. Lambdauttrykket er det andre argumentet til otherfn (), kalt main (). Merk at lambda-funksjonen (uttrykk) ikke ender med semikolon i denne samtalen, fordi det her er et argument (ikke en frittstående funksjon).

Lambda-funksjonsparameteren i definisjonen av otherfn () -funksjonen er en peker til en funksjon. Pekeren har navnet, ptr. Navnet, ptr, brukes i den andrefn () definisjonen for å kalle lambda-funksjonen.

Uttalelsen,

    int no2 = (* ptr) (2);

I otherfn () -definisjonen kaller den lambdafunksjonen med argumentet 2. Returverdien for samtalen, "(* ptr) (2)" fra lambda-funksjonen, er tildelt nr. 2.

Ovennevnte program viser også hvordan lambda-funksjonen kan brukes i C ++ tilbakekallingsfunksjonen.

Deler av Lambda Expression

Delene av en typisk lambda-funksjon er som følger:

    [] ()
  • [] er fangstklausulen. Det kan ha gjenstander.
  • () er for parameterlisten.
  • er for funksjonsdelen. Hvis funksjonen står alene, bør den ende med semikolon.

Fanger

Lambda-funksjonsdefinisjonen kan tilordnes en variabel eller brukes som argument for en annen funksjonsanrop. Definisjonen for en slik funksjonsanrop skal ha som parameter en peker til en funksjon som tilsvarer lambdafunksjonens definisjon.

Lambda-funksjonsdefinisjonen er forskjellig fra normal funksjonsdefinisjon. Den kan tilordnes en variabel i det globale omfanget; denne funksjonen-tilordnet-til-variabelen kan også kodes i en annen funksjon. Når den er tildelt en global variabel, kan kroppen se andre variabler i det globale omfanget. Når den er tildelt en variabel i en normal funksjonsdefinisjon, kan kroppen se andre variabler i funksjonsomfanget bare med fangstklausulens hjelp, [].

Fangsparagrafen [], også kjent som lambda-introdusenten, lar variabler sendes fra det omgivende (funksjons) omfanget til lambda-uttrykkets funksjonslegeme. Lambdauttrykkets funksjonskropp sies å fange variabelen når den mottar objektet. Uten fangstklausulen [] kan en variabel ikke sendes fra det omgivende omfanget inn i lambdauttrykkets funksjonslegeme. Følgende program illustrerer dette, med hovedfunksjonen (), som det omliggende omfanget:

#inkludere
bruker navneområde std;
int main ()

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

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

Resultatet er 5. Uten navnet, id, inne i [], ville ikke lambdauttrykket sett variabelen id til hovedfunksjonen ().

Fange etter referanse

Ovennevnte bruk av fangstklausulen er å fange etter verdi (se detaljer nedenfor). I fangst med referanse, plasseringen (lagring) av variabelen, f.eks.g., id over, av det omkringliggende omfanget, blir gjort tilgjengelig inne i lambdafunksjonskroppen. Så hvis du endrer verdien på variabelen i lambdafunksjonens kropp, endres verdien på den samme variabelen i det omliggende omfanget. Hver variabel som er gjentatt i fangstklausulen, er foran med ampersand (&) for å oppnå dette. Følgende program illustrerer dette:

#inkludere
bruker navneområde std;
int main ()

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

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

Utgangen er:

    6, 3.4, B

Bekrefter at variabelnavnene inne i lambdauttrykkets funksjonslegeme er for de samme variablene utenfor lambdauttrykket.

Fange etter verdi

Ved å fange etter verdi blir en kopi av variabelens plassering, av det omkringliggende omfanget, tilgjengelig i lambdafunksjonens kropp. Selv om variabelen inne i lambdafunksjonen er en kopi, kan verdien ikke endres i kroppen fra nå av. For å oppnå fangst etter verdi, går ikke hver variabel som er gjentatt i fangstklausulen, foran noe. Følgende program illustrerer dette:

#inkludere
bruker navneområde std;
int main ()

int id = 5; flyte 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';
retur 0;

Utgangen er:

5, 2.3, A
6, 3.4, B

Hvis kommentarindikatoren blir fjernet, kompileres ikke programmet. Kompilatoren vil gi en feilmelding om at variablene i funksjonslegemets definisjon av lambdauttrykket ikke kan endres. Selv om variablene ikke kan endres i lambdafunksjonen, kan de endres utenfor lambdafunksjonen, som programmet ovenfor viser.

Blanding av fanger

Fange med referanse og fange etter verdi kan blandes, som følgende program viser:

#inkludere
bruker navneområde std;
int main ()

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

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

Utgangen er:

    5, 2.3, B, 0

Når alle er fanget, blir de referert:

Hvis alle variablene som skal fanges, blir fanget opp ved referanse, er det bare én & som er tilstrekkelig i fangstklausulen. Følgende program illustrerer dette:

#inkludere
bruker navneområde std;
int main ()

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

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

Utgangen er:

6, 3.4, B, 0

Hvis noen variabler skal fanges med referanse og andre etter verdi, vil en & representere alle referansene, og resten vil hver ikke bli innledet av noe, som følgende program viser:

bruker navneområde std;
int main ()

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

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

Utgangen er:

5, 2.3, B, 0

Legg merke til at & alene (i.e., & ikke etterfulgt av en identifikator) må være det første tegnet i fangstklausulen.

Når alle er fanget, er de etter verdi:

Hvis alle variablene som skal fanges, skal fanges opp av verdi, vil bare en = være tilstrekkelig i fangstklausulen. Følgende program illustrerer dette:

#inkludere
bruker navneområde std;
int main ()

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

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

Utgangen er:

5, 2.3, A, 1

Merk: = er skrivebeskyttet, per nå.

Hvis noen variabler skal fanges opp av verdi og andre som referanse, vil en = representere alle de skrivebeskyttede kopierte variablene, og resten vil hver ha &, som følgende program viser:

#inkludere
bruker navneområde std;
int main ()

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

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

Utgangen er:

5, 2.3, B, 0

Merk at = alene må være det første tegnet i fangstklausulen.

Klassisk tilbakeringingsfunksjonsskjema med Lambda-uttrykk

Følgende program viser hvordan en klassisk tilbakekallingsfunksjon kan gjøres med lambda-uttrykket:

#inkludere
bruker navneområde std;
char * utgang;
auto cba = [] (char out [])

utgang = ut;
;
void principalFunc (char input [], void (* pt) (char []))

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

ugyldig fn ()

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

int main ()

char input [] = "for tilbakeringingsfunksjon";
principalFunc (input, cba);
fn ();
cout<retur 0;

Utgangen er:

for hovedfunksjon

for tilbakeringingsfunksjon

Husk at når en lambda-uttrykkdefinisjon er tildelt en variabel i det globale omfanget, kan dens funksjonslegeme se globale variabler uten å bruke fangstklausulen.

Den etterfølgende retur-typen

Returtypen til et lambdauttrykk er automatisk, noe som betyr at kompilatoren bestemmer returtypen fra returuttrykket (hvis det finnes). Hvis programmereren virkelig vil indikere returtypen, vil han gjøre det som i følgende program:

#inkludere
bruker navneområde std;
auto fn = [] (int param) -> int

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

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

Utgangen er 5. Etter parameterlisten skrives piloperatøren. Dette etterfølges av returtypen (int i dette tilfellet).

Lukking

Vurder 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 som vil bli instantiert fra struct-klassen. Lambda-uttrykk er likt i implementeringen. Lambdafunksjonens definisjon er en slags klasse. Når lambda-funksjonen kalles (påkalt), blir et objekt instansiert fra definisjonen. Dette objektet kalles en lukking. Det er nedleggelsen som gjør det arbeidet lambda forventes å gjøre.

Imidlertid vil koding av lambda-uttrykket som strukturen ovenfor ha obj1 og obj2 erstattet av de tilsvarende parameternes argumenter. Følgende program illustrerer dette:

#inkludere
bruker navneområde std;
auto fn = [] (int param1, int param2)

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

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

Utgangen er 5. Argumentene er 2 og 3 i parentes. Merk at lambda-uttrykksfunksjonen call, fn, ikke tar noe argument siden argumentene allerede er kodet på slutten av lambda-funksjonsdefinisjonen.

Konklusjon

Lambdauttrykket er en anonym funksjon. Det er i to deler: klasse og objekt. Definisjonen er en slags klasse. Når uttrykket kalles, dannes et objekt fra definisjonen. Dette objektet kalles en lukking. Det er nedleggelsen som gjør det arbeidet lambda forventes å gjøre.

For at lambdauttrykket skal motta en variabel fra et ytre funksjonsomfang, trenger det en ikke-tom fangstklausul i funksjonslegemet.

Mus Microsoft Sculpt Touch Wireless Mouse Review
Microsoft Sculpt Touch Wireless Mouse Review
Jeg har nylig lest om Microsoft Sculpt Touch trådløs mus og bestemte meg for å kjøpe den. Etter å ha brukt den en stund bestemte jeg meg for å dele mi...
Mus AppyMouse Pekeplate og musepeker på skjermen for Windows-nettbrett
AppyMouse Pekeplate og musepeker på skjermen for Windows-nettbrett
Nettbrettbrukere savner ofte musepekeren, spesielt når de bruker vanlige bærbare datamaskiner. Berøringsskjermen Smarttelefoner og nettbrett har mange...
Mus Midterste museknapp fungerer ikke i Windows 10
Midterste museknapp fungerer ikke i Windows 10
De midtre museknapp hjelper deg med å bla gjennom lange websider og skjermer med mye data. Hvis det stopper, vil du ende opp med å bruke tastaturet ti...