Varför Lambda Expression?
Tänk på följande uttalande:
int mynt = 52;Här är myInt en identifierare, en lvalue. 52 är en bokstavlig, en prvalue. Idag är det möjligt att koda en funktion speciellt och placera den i läget 52. En sådan funktion kallas ett lambdauttryck. Tänk också på följande korta program:
#omfattaanvänder namnrymd std;
int fn (int par)
int svar = par + 3;
returnera svaret;
int main ()
fn (5);
returnera 0;
Idag är det möjligt att koda en funktion speciellt och placera den i läget för argumentet 5, för funktionsanropet, fn (5). En sådan funktion kallas ett lambdauttryck. Lambdauttrycket (funktionen) i den positionen är ett värde.
Alla bokstäver utom strängen bokstavlig är en prvalue. Lambdauttrycket är en speciell funktionsdesign som passar som en bokstavlig kod. Det är en anonym (ej namngiven) funktion. Den här artikeln förklarar det nya C ++ primära uttrycket, kallat lambdauttrycket. Grundläggande kunskaper i C ++ är ett krav för att förstå den här artikeln.
Artikelinnehåll
- Illustration av Lambdauttryck
- Delar av Lambda Expression
- Fångar
- Klassiskt återuppringningsfunktionsschema med Lambda-uttryck
- Den bakre-retur-typen
- Stängning
- Slutsats
Illustration av Lambdauttryck
I följande program tilldelas en funktion, som är ett lambdauttryck, en variabel:
#omfattaanvänder namnrymd std;
auto fn = [] (int param)
int svar = param + 3;
returnera svaret;
;
int main ()
auto variab = fn (2);
cout << variab << '\n';
returnera 0;
Utgången är:
5Utanför huvudfunktionen () finns variabeln, fn. Dess typ är auto. Auto i denna situation innebär att den faktiska typen, såsom int eller float, bestäms av rätt operand för uppdragsoperatören (=). Till höger om uppdragsoperatören finns ett lambdauttryck. Ett lambdauttryck är en funktion utan föregående returtyp. Notera användningen och placeringen av hakparenteserna, []. Funktionen returnerar 5, ett int, som bestämmer typen för fn.
I huvudfunktionen () finns uttalandet:
auto variab = fn (2);Detta betyder att fn utanför main () hamnar som identifierare för en funktion. Dess implicita parametrar är de för lambdauttrycket. Typen för variab är auto.
Observera att lambdauttrycket slutar med ett semikolon, precis som klass- eller strukturdefinitionen, slutar med ett semikolon.
I följande program är en funktion, som är ett lambdauttryck som returnerar värdet 5, ett argument till en annan funktion:
#omfattaanvänder namnrymd std;
ogiltig otherfn (int no1, int (* ptr) (int))
int no2 = (* ptr) (2);
cout << no1 << " << no2 << '\n';
int main ()
otherfn (4, [] (int param)
int svar = param + 3;
returnera svaret;
);
returnera 0;
Utgången är:
4 5Det finns två funktioner här, lambdauttrycket och funktionen otherfn (). Lambdauttrycket är det andra argumentet för otherfn (), som kallas main (). Observera att lambdafunktionen (uttryck) inte slutar med semikolon i det här samtalet eftersom det här är ett argument (inte en fristående funktion).
Lambdafunktionsparametern i definitionen av den andrafn () -funktionen är en pekare till en funktion. Pekaren har namnet ptr. Namnet, ptr, används i definitionen av otherfn () för att kalla lambda-funktionen.
Påståendet,
int no2 = (* ptr) (2);I definitionen otherfn () kallar den lambdafunktionen med argumentet 2. Returvärdet för samtalet, "(* ptr) (2)" från lambdafunktionen, tilldelas nr 2.
Ovanstående program visar också hur lambdafunktionen kan användas i C ++ återuppringningsfunktionsschemat.
Delar av Lambda Expression
Delarna av en typisk lambdafunktion är som följer:
[] ()- [] är fångstklausulen. Det kan ha föremål.
- () är för parameterlistan.
- är för funktionskroppen. Om funktionen står ensam ska den avslutas med ett semikolon.
Fångar
Lambdafunktionsdefinitionen kan tilldelas en variabel eller användas som argument för ett annat funktionsanrop. Definitionen för ett sådant funktionsanrop bör ha som parameter en pekare till en funktion som motsvarar lambdafunktionsdefinitionen.
Lambdafunktionsdefinitionen skiljer sig från den normala funktionsdefinitionen. Den kan tilldelas en variabel i det globala omfånget; den här funktionstilldelade variabeln kan också kodas inuti en annan funktion. När den tilldelas en global omfattningsvariabel kan dess kropp se andra variabler i det globala omfånget. När den tilldelas en variabel i en normal funktionsdefinition kan dess kropp se andra variabler i funktionsomfånget endast med hjälp av fångstklausulen, [].
Fångningsklausulen [], även känd som lambda-introduceraren, tillåter att variabler skickas från det omgivande (funktions) omfånget till lambdauttryckets funktionskropp. Lambdauttryckets funktionskropp sägs fånga variabeln när den tar emot objektet. Utan fångstklausulen [] kan en variabel inte skickas från det omgivande omfånget till lambdauttryckets funktionskropp. Följande program illustrerar detta, med huvudområdet () funktionsomfång, som det omgivande omfånget:
#omfattaanvänder namnrymd std;
int main ()
int id = 5;
auto fn = [id] ()
cout << id << '\n';
;
fn ();
returnera 0;
Utgången är 5. Utan namnet, id, inuti [], skulle lambdauttrycket inte ha sett variabeln id för huvudfunktionsomfånget ().
Fånga med referens
Ovanstående exempel på användning av fångstklausulen är att fånga efter värde (se detaljer nedan). Vid hämtning av referens, variabelns placering (lagring), e.g., id ovan, av det omgivande omfånget, görs tillgängligt inuti lambdafunktionskroppen. Så om du ändrar värdet på variabeln inuti lambdafunktionens kropp kommer värdet på samma variabel att ändras i det omgivande omfånget. Varje variabel som upprepas i fångstklausulen föregås av bokstaven (&) för att uppnå detta. Följande program illustrerar detta:
#omfattaanvänder namnrymd std;
int main ()
int id = 5; float ft = 2.3; char ch = 'A';
auto fn = [& id, & ft, & ch] ()
id = 6; ft = 3.4; ch = 'B';
;
fn ();
cout << id << ", " << ft << ", " << ch << '\n';
returnera 0;
Utgången är:
6, 3.4, BBekräftar att variabelnamnen inuti lambdauttryckets funktionskropp är för samma variabler utanför lambdauttrycket.
Fånga efter värde
För att fånga efter värde görs en kopia av variabelns läge, med det omgivande omfånget, tillgängligt inuti lambdafunktionens kropp. Även om variabeln inuti lambdafunktionens kropp är en kopia, kan dess värde inte ändras inuti kroppen från och med nu. För att uppnå fångst efter värde föregås inte varje variabel som upprepas i fångstklausulen med någonting. Följande program illustrerar detta:
#omfattaanvänder namnrymd std;
int main ()
int id = 5; float 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';
returnera 0;
Utgången är:
5, 2.3, A6, 3.4, B
Om kommentarindikatorn tas bort kommer programmet inte att kompileras. Kompilatorn ger ett felmeddelande om att variablerna i funktionskroppens definition av lambdauttrycket inte kan ändras. Även om variablerna inte kan ändras inuti lambdafunktionen kan de ändras utanför lambdafunktionen, som ovanstående programs utdata visar.
Blandning av fångster
Fånga med referens och fånga efter värde kan blandas, som följande program visar:
#omfattaanvänder namnrymd std;
int main ()
int id = 5; float ft = 2.3; char ch = 'A'; bool bl = sant;
auto fn = [id, ft, & ch, & bl] ()
ch = 'B'; bl = falskt;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
returnera 0;
Utgången är:
5, 2.3, B, 0När alla fångas, är de som referens:
Om alla variabler som ska fångas fångas genom referens, räcker det bara med en & i fångstklausulen. Följande program illustrerar detta:
#omfattaanvänder namnrymd std;
int main ()
int id = 5; float ft = 2.3; char ch = 'A'; bool bl = sant;
auto fn = [&] ()
id = 6; ft = 3.4; ch = 'B'; bl = falskt;
;
fn ();
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
returnera 0;
Utgången är:
6, 3.4, B, 0Om vissa variabler ska fångas genom referens och andra efter värde, representerar en & alla referenser, och resten kommer vardera inte att föregås av något, som följande program visar:
använder namnrymd std;int main ()
int id = 5; float ft = 2.3; char ch = 'A'; bool bl = sant;
auto fn = [&, id, ft] ()
ch = 'B'; bl = falskt;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
returnera 0;
Utgången är:
5, 2.3, B, 0Observera att & ensam (i.e., & inte följt av en identifierare) måste vara det första tecknet i fångstklausulen.
När alla fångas är efter värde:
Om alla variabler som ska fångas ska fångas av värde, räcker bara en = i fångstklausulen. Följande program illustrerar detta:
#omfattaanvänder namnrymd std;
int main ()
int id = 5; float ft = 2.3; char ch = 'A'; bool bl = sant;
auto fn = [=] ()
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
returnera 0;
Utgången är:
5, 2.3, A, 1Notera: = är skrivskyddad från och med nu.
Om vissa variabler ska fångas av värde och andra som referens, representerar en = alla skrivskyddade kopierade variabler, och resten har vardera &, som följande program visar:
#omfattaanvänder namnrymd std;
int main ()
int id = 5; float ft = 2.3; char ch = 'A'; bool bl = sant;
auto fn = [=, & ch, & bl] ()
ch = 'B'; bl = falskt;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
returnera 0;
Utgången är:
5, 2.3, B, 0Observera att = ensam måste vara det första tecknet i fångstklausulen.
Klassiskt återuppringningsfunktionsschema med Lambda-uttryck
Följande program visar hur ett klassiskt återuppringningsfunktionsschema kan göras med lambdauttrycket:
#omfattaanvänder namnrymd std;
char * output;
auto cba = [] (char out [])
utgång = ut;
;
void principalFunc (char input [], void (* pt) (char []))
(* pt) (ingång);
cout<<"for principal function"<<'\n';
ogiltigt fn ()
cout<<"Now"<<'\n';
int main ()
char input [] = "för återuppringningsfunktion";
principalFunc (input, cba);
fn ();
cout<