Hvorfor Lambda -uttrykk?
Tenk på følgende uttalelse:
int myint = 52;
Her er Myint en identifikator, en lValue. 52 er en bokstavelig, en prvalue. I dag er det mulig å kode en funksjon spesielt og sette den i posisjonen til 52. En slik funksjon kalles et lambda -uttrykk. Vurder også følgende korte program:
#inkludere
ved hjelp av navneområdet STD;
int fn (int par)
int svar = par + 3;
return svar;
int main ()
fn (5);
return 0;
I dag er det mulig å kode en funksjon spesielt og sette den i stillingen til argumentet til 5, for funksjonssamtalen, FN (5). En slik funksjon kalles et lambda -uttrykk. Lambda -uttrykket (funksjon) i den posisjonen er en prvalue.
Enhver bokstavelig unntatt strengen bokstavelig er en prvalue. Lambda -uttrykket er en spesiell funksjonsdesign som vil passe som en bokstavelig i kode. Det er en anonym (ikke navngitt) funksjon. Denne artikkelen forklarer det nye C ++ primære uttrykket, kalt Lambda -uttrykket. Grunnleggende kunnskap i C ++ er et krav for å forstå denne artikkelen.
Artikkelinnhold
Illustrasjon av lambda -uttrykk
I det følgende programmet er en funksjon, som er et lambda -uttrykk, tilordnet en variabel:
#inkludere
ved hjelp av navneområdet STD;
auto fn = [] (int param)
int svar = param + 3;
return svar;
;
int main ()
auto variab = fn (2);
cout << variab << '\n';
return 0;
Utgangen er:
5Utenfor hovedfunksjonen () er det variabelen, fn. Typen er auto. Auto i denne situasjonen betyr at den faktiske typen, for eksempel Int eller Float, bestemmes av riktig operand til tildelingsoperatøren (=). Til høyre for tildelingsoperatøren er et lambda -uttrykk. Et lambda -uttrykk er en funksjon uten foregående returtype. Legg merke til bruken og plasseringen av de firkantede parentesene, []. Funksjonen returnerer 5, en int, som vil avgjøre typen for FN.
I hovedfunksjonen () er det uttalelsen:
auto variab = fn (2);
Dette betyr, FN utenfor Main (), ender opp som identifikator for en funksjon. Dets implisitte parametere er de fra Lambda -uttrykket. Typen for variab er auto.
Merk at Lambda -uttrykket ender med en semikolon, akkurat som klassen eller strukturdefinisjonen, ender med en semikolon.
I det følgende programmet er en funksjon, som er et lambda -uttrykk som returnerer verdien av 5, et argument for en annen funksjon:
#inkludere
ved hjelp av navneområdet STD;
void otherfn (int no1, int (*ptr) (int))
int no2 = (*ptr) (2);
cout << no1 << " << no2 << '\n';
int main ()
OtherFn (4, [] (int param)
int svar = param + 3;
return svar;
);
return 0;
Utgangen er:
4 5Det er to funksjoner her, lambda -uttrykket og andrefn () -funksjonen. Lambda -uttrykket er det andre argumentet til OtherFN (), kalt i Main (). Merk at lambda-funksjonen (uttrykket) ikke ender med en semikolon i denne samtalen fordi her er det 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 definisjonen av andrefn () for å kalle lambda -funksjonen.
Uttalelsen,
int no2 = (*ptr) (2);
I definisjonen av andrefn () kaller den lambda -funksjonen med et argument fra 2. Returverdien av samtalen, "(*PTR) (2)" fra Lambda -funksjonen, er tilordnet NO2.
Ovennevnte program viser også hvordan lambda -funksjonen kan brukes i C ++ tilbakeringingsfunksjonsordning.
Deler av lambda -uttrykk
Delene av en typisk lambda -funksjon er som følger:
[] ()
Fanger
Lambda -funksjonsdefinisjonen kan tilordnes en variabel eller brukes som argument til en annen funksjonssamtale. Definisjonen for en slik funksjonssamtale skal ha som en parameter, en peker til en funksjon, tilsvarende Lambda -funksjonsdefinisjonen.
Lambda -funksjonsdefinisjonen er forskjellig fra den normale funksjonsdefinisjonen. Det kan tilordnes en variabel i det globale omfanget; Denne funksjonen tilordne til variabel kan også kodes i en annen funksjon. Når den er tilordnet en global omfangsvariabel, kan kroppen se andre variabler i det globale omfanget. Når den er tilordnet en variabel i en normal funksjonsdefinisjon, kan kroppen se andre variabler i funksjonsomfanget bare med fangstklausulens hjelp, [].
Capture Clause [], også kjent som lambda-introduseren, lar variabler sendes fra det omkringliggende (funksjonen) omfanget til lambda-uttrykkens funksjonskropp. Lambda -uttrykkens funksjonsorgan sies å fange variabelen når den mottar objektet. Uten fangstbestemmelsen [] kan en variabel ikke sendes fra det omkringliggende omfanget inn i Lambda -uttrykkens funksjonskropp. Følgende program illustrerer dette, med hovedfunksjonen (), som det omkringliggende omfanget:
#inkludere
ved hjelp av navneområdet STD;
int main ()
int id = 5;
auto fn = [id] ()
cout << id << '\n';
;
fn ();
return 0;
Utgangen er 5. Uten navnet, ID, inne i [], ville ikke Lambda -uttrykket ha sett den variable ID for hovedfunksjonen ().
Fange med referanse
Ovennevnte eksempelbruk av fangstklausulen er fangst etter verdi (se detaljer nedenfor). Ved å fange med referanse, plasseringen (lagring) av variabelen, e.g., ID ovenfor, av det omkringliggende omfanget, blir gjort tilgjengelig inne i Lambda -funksjonskroppen. Så å endre verdien på variabelen i lambda -funksjonen kropp vil endre verdien av den samme variabelen i det omkringliggende omfanget. Hver variabel gjentatt i fangstklausulen er gitt av Ampersand (&) for å oppnå dette. Følgende program illustrerer dette:
#inkludere
ved hjelp av navneområdet 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';
return 0;
Utgangen er:
6, 3.4, bBekreftelse av at variabelnavnene i Lambda -uttrykkens funksjonskropp er for de samme variablene utenfor lambda -uttrykket.
Fange etter verdi
I fangst av verdi blir en kopi av variabelenes beliggenhet, av det omkringliggende omfanget, gjort tilgjengelig i Lambda -funksjonen. Selv om variabelen inne i lambda -funksjonen er en kopi, kan den ikke endres i kroppen i kroppen per nå. For å oppnå fangst etter verdi, blir ikke hver variabel gjentatt i fangstklausulen gitt noe av noe. Følgende program illustrerer dette:
#inkludere
ved hjelp av navneområdet 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';
return 0;
Utgangen er:
5, 2.3, aHvis kommentarindikatoren fjernes, vil ikke programmet sammenstille. Kompilatoren vil utstede en feilmelding som variablene i funksjonskroppens definisjon av lambda -uttrykket ikke kan endres. Selv om variablene ikke kan endres inne i lambda -funksjonen, kan de endres utenfor lambda -funksjonen, som ovennevnte utdata viser.
Blanding av fangster
Å fange opp med referanse og fange etter verdi kan blandes, som følgende program viser:
#inkludere
ved hjelp av navneområdet 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 ();
return 0;
Utgangen er:
5, 2.3, B, 0Når alle er tatt til fange, er referanse:
Hvis alle variabler som skal fanges opp blir fanget med referanse, er det bare en og vil være tilstrekkelig i fangstklausulen. Følgende program illustrerer dette:
#inkludere
ved hjelp av navneområdet 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';
return 0;
Utgangen er:
6, 3.4, B, 0Hvis noen variabler skal fanges opp som referanse og andre etter verdi, vil en og vil representere alle referanser, og resten vil ikke bli gitt noen av noe, som følgende program viser:
#inkludere
ved hjelp av navneområdet 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 ();
return 0;
Utgangen er:
5, 2.3, B, 0Legg merke til at & alene (jeg.e., og ikke fulgt av en identifikator) må være den første karakteren i fangstklausulen.
Når alle er fanget, er det etter verdi:
Hvis alle variabler som skal fanges opp, skal fanges opp etter verdi, vil bare ett = være tilstrekkelig i fangstklausulen. Følgende program illustrerer dette:
#inkludere
ved hjelp av navneområdet 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 ();
return 0;
Utgangen er:
5, 2.3, a, 1Merk: = er skrivebeskyttet, per nå.
Hvis noen variabler skal fanges opp etter verdi og andre med referanse, vil en = representere alle de skrivebeskyttede kopierte variablene, og resten vil ha og, som følgende program viser:
#inkludere
ved hjelp av navneområdet 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 ();
return 0;
Utgangen er:
5, 2.3, B, 0Legg merke til at = alene må være den første karakteren i fangstklausulen.
Klassisk tilbakeringingsfunksjonsskjema med Lambda -uttrykk
Følgende program viser hvordan et klassisk tilbakeringingsfunksjonsskjema kan gjøres med Lambda -uttrykket:
#inkludere
ved hjelp av navneområdet STD;
char *output;
auto cba = [] (char out [])
utgang = ut;
;
void PrincipalFunc (Char Input [], Void (*PT) (Char []))
(*pt) (input);
cout<<"for principal function"<<'\n';
ugyldig fn ()
cout<<"Now"<<'\n';
int main ()
char input [] = "for tilbakeringingsfunksjon";
PrincipalFunc (input, CBA);
fn ();
cout<
Utgangen er:
for hovedfunksjonHusk at når en Lambda -ekspresjonsdefinisjon er tildelt en variabel i det globale omfanget, kan dens funksjonsorgan se globale variabler uten å bruke fangstklausulen.
Turv-retur-typen
Returtypen til et lambda -uttrykk er auto, noe som betyr at kompilatoren bestemmer returtypen fra returuttrykket (hvis den er til stede). Hvis programmereren virkelig ønsker å indikere returtypen, vil han gjøre det som i følgende program:
#inkludere
ved hjelp av navneområdet STD;
auto fn = [] (int param) -> int
int svar = param + 3;
return svar;
;
int main ()
auto variab = fn (2);
cout << variab << '\n';
retur 0;
Utgangen er 5. Etter parameterlisten er piloperatøren skrevet. Dette blir fulgt av returtypen (int i dette tilfellet).
Lukking
Tenk på følgende kodesegment:
struct cla
int id = 5;
char ch = 'a';
obj1, obj2;
Her er CLA navnet på Struct Class. OBJ1 og OBJ2 er to objekter som vil bli instantiert fra Struct Class. Lambda -uttrykk er likt i implementeringen. Lambda -funksjonsdefinisjonen er en slags klasse. Når lambda -funksjonen kalles (påkalt), blir et objekt instantiert 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
ved hjelp av navneområdet STD;
Auto fn = [] (int param1, int param2)
int svar = param1 + param2;
return svar;
(2, 3);
int main ()
auto var = fn;
cout << var << '\n';
retur 0;
Utgangen er 5. Argumentene er 2 og 3 i parenteser. Merk at lambda -uttrykksfunksjonen, FN, ikke tar noe argument siden argumentene allerede er kodet på slutten av Lambda -funksjonsdefinisjonen.
Konklusjon
Lambda -uttrykket er en anonym funksjon. Det er i to deler: klasse og objekt. Definisjonen er en slags klasse. Når uttrykket blir kalt, dannes et objekt fra definisjonen. Dette objektet kalles en lukking. Det er nedleggelsen som gjør det arbeidet lambda forventes å gjøre. For at Lambda-uttrykket skal motta en variabel fra et ytre funksjonsomfang, trenger det en ikke-tom fangstklausul i funksjonskroppen.