C ++

Lambda výrazy v C ++

Lambda výrazy v C ++

Prečo lambda výraz?

Zvážte nasledujúce vyhlásenie:

    int myInt = 52;

MyInt je identifikátor, hodnota l. 52 je literál, prvalue. Dnes je možné špeciálne kódovať funkciu a umiestniť ju na pozíciu 52. Takáto funkcia sa nazýva výraz lambda. Zvážte tiež nasledujúci krátky program:

#include
pomocou namespace std;
int fn (int par)

int odpoveď = par + 3;
spätná odpoveď;

int main ()

fn (5);
návrat 0;

Dnes je možné špeciálne kódovať funkciu a umiestniť ju do polohy argumentu 5, volania funkcie, fn (5). Takáto funkcia sa nazýva výraz lambda. Výraz (funkcia) lambda v tejto polohe je prvalue.

Akýkoľvek literál okrem reťazcového literálu je prvalue. Výraz lambda je návrh špeciálnej funkcie, ktorý by sa hodil ako literál v kóde. Je to anonymná (nepomenovaná) funkcia. Tento článok vysvetľuje nový primárny výraz C ++, ktorý sa nazýva výraz lambda. Na pochopenie tohto článku sú potrebné základné znalosti v jazyku C ++.

Obsah článku

  • Ilustrácia lambda výrazu
  • Časti výrazu lambda
  • Zachytáva
  • Schéma klasického spätného volania s výrazom lambda
  • Typ s koncovým návratom
  • Uzavretie
  • Záver

Ilustrácia lambda výrazu

V nasledujúcom programe je k premennej priradená funkcia, ktorá je výrazom lambda

#include
pomocou namespace std;
auto fn = [] (int param)

int odpoveď = param + 3;
spätná odpoveď;
;
int main ()

automatická premenná = fn (2);
cout << variab << '\n';
návrat 0;

Výstup je:

    5

Mimo funkcie main () je premenná fn. Jeho typ je auto. Auto v tejto situácii znamená, že skutočný typ, napríklad int alebo float, je určený pravým operandom operátora priradenia (=). Na pravej strane operátora priradenia je výraz lambda. Výraz lambda je funkcia bez predchádzajúceho návratového typu. Všimnite si použitie a polohu hranatých zátvoriek, []. Funkcia vráti 5, int, ktoré určia typ pre fn.

Vo funkcii main () je príkaz:

    automatická premenná = fn (2);

To znamená, že fn mimo main () končí ako identifikátor funkcie. Jeho implicitné parametre sú parametre výrazu lambda. Typ pre premennú je auto.

Upozorňujeme, že výraz lambda končí bodkočiarkou, rovnako ako definícia triedy alebo štruktúry, končí bodkočiarkou.

V nasledujúcom programe je funkcia, ktorá je výrazom lambda vracajúcim hodnotu 5, argumentom pre inú funkciu:

#include
pomocou namespace std;
void otherfn (int no1, int (* ptr) (int))

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

int main ()

otherfn (4, [] (int param)

int odpoveď = param + 3;
spätná odpoveď;
);
návrat 0;

Výstup je:

    4 5

Existujú tu dve funkcie, výraz lambda a funkcia otherfn (). Výraz lambda je druhým argumentom otherfn (), ktorý sa volá main (). Upozorňujeme, že funkcia (výraz) lambda v tomto volaní nekončí bodkočiarkou, pretože tu ide o argument (nie samostatnú funkciu).

Parameter funkcie lambda v definícii funkcie otherfn () je ukazovateľ na funkciu. Ukazovateľ má názov, ptr. Názov ptr sa v definícii otherfn () používa na volanie funkcie lambda.

Výkaz,

    int no2 = (* ptr) (2);

V definícii otherfn () volá funkciu lambda s argumentom 2. Návratová hodnota hovoru „(* ptr) (2)“ z funkcie lambda je priradená číslu 2.

Vyššie uvedený program tiež ukazuje, ako je možné použiť funkciu lambda v schéme funkcií spätného volania C ++.

Časti výrazu lambda

Časti typickej funkcie lambda sú nasledovné:

    [] ()
  • [] je doložka o zajatí. Môže obsahovať položky.
  • () je pre zoznam parametrov.
  • je pre telo funkcie. Ak je funkcia samostatne stojaca, mala by sa končiť bodkočiarkou.

Zachytáva

Definíciu funkcie lambda je možné priradiť k premennej alebo použiť ako argument na volanie inej funkcie. Definícia takéhoto volania funkcie by mala mať ako parameter, ukazovateľ na funkciu, zodpovedajúci definícii funkcie lambda.

Definícia funkcie lambda sa líši od definície normálnej funkcie. Môže byť priradený k premennej v globálnom rozsahu; túto funkciu priradenú k premennej je možné kódovať aj v rámci inej funkcie. Keď je priradený k premennej globálneho rozsahu, jej telo uvidí ďalšie premenné v globálnom rozsahu. Keď je priradená k premennej v rámci definície normálnej funkcie, jej telo vidí ďalšie premenné v rozsahu funkcie iba s pomocou doložky o zachytení, [].

Klauzula o zachytení [], známa tiež ako zavádzač lambda, umožňuje posielať premenné z okolitého (funkčného) rozsahu do tela funkcie výrazu lambda. Telo funkcie výrazu lambda údajne zachytí premennú, keď prijme objekt. Bez klauzuly o zachytení [] nie je možné poslať premennú z okolitého rozsahu do tela funkcie výrazu lambda. Nasledujúci program to ilustruje s rozsahom funkcií main () ako okolitým rozsahom:

#include
pomocou namespace std;
int main ()

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

cout << id << '\n';
;
fn ();
návrat 0;

Výstup je 5. Bez názvu, id, vo vnútri [] by výraz lambda nevidel premennú id rozsahu funkcie main ().

Zachytávanie referenciou

Vyššie uvedené použitie klauzuly na zachytávanie je zachytávanie podľa hodnoty (podrobnosti nájdete nižšie). Pri zachytávaní pomocou referencie je umiestnenie (úložisko) premennej, napr.g., vyššie uvedené, okolitého rozsahu, je k dispozícii vo vnútri tela funkcie lambda. Takže zmena hodnoty premennej vo vnútri tela funkcie lambda zmení hodnotu tej istej premennej v okolitom rozsahu. Na dosiahnutie tejto hodnoty je pred každou premennou opakovanou v doložke capture ampersand (&). Nasledujúci program to ilustruje:

#include
pomocou namespace 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';
návrat 0;

Výstup je:

    6, 3.4, B

Potvrdenie, že názvy premenných vo vnútri tela funkcie výrazu lambda sú pre rovnaké premenné mimo výrazu lambda.

Zachytávanie podľa hodnoty

Pri snímaní podľa hodnoty je vo vnútri tela funkcie lambda k dispozícii kópia umiestnenia premennej, obklopujúceho rozsahu. Aj keď premenná vo vnútri tela funkcie lambda je kópia, jej hodnotu už teraz nemožno vo vnútri tela meniť. Aby sa dosiahlo zachytenie podľa hodnoty, každej premennej opakovanej v doložke zachytenia nič nepredchádza. Nasledujúci program to ilustruje:

#include
pomocou namespace 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';
návrat 0;

Výstup je:

5, 2.3, A
6, 3.4, B

Ak je indikátor komentára odstránený, program sa nezkompiluje. Kompilátor vydá chybové hlásenie, že premenné vo vnútri definície tela výrazu lambda nie je možné zmeniť. Aj keď premenné nie je možné meniť vo vnútri funkcie lambda, je možné ich meniť aj mimo funkcie lambda, ako ukazuje výstup vyššie uvedeného programu.

Mixing Captures

Zachytávanie pomocou referencie a zachytávanie podľa hodnoty je možné kombinovať, ako ukazuje nasledujúci program:

#include
pomocou namespace std;
int main ()

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

ch = 'B'; bl = false;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
návrat 0;

Výstup je:

    5, 2.3, B, 0

Keď sú všetky zachytené, sú odkazom:

Ak sú všetky premenné, ktoré sa majú zachytiť, zachytené odkazom, potom v doložke zachytenia postačí iba jedna &. Nasledujúci program to ilustruje:

#include
pomocou namespace std;
int main ()

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

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

Výstup je:

6, 3.4, B, 0

Ak majú byť niektoré premenné zachytené pomocou referencie a iné podľa hodnoty, potom jedna & bude predstavovať všetky referencie a zvyšku nebude nič predchádzať, ako ukazuje nasledujúci program:

pomocou namespace std;
int main ()

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

ch = 'B'; bl = false;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
návrat 0;

Výstup je:

5, 2.3, B, 0

Všimnite si, že & sám (t.j.e., a za ktorým nenasleduje identifikátor) musí byť prvý znak v doložke zachytenia.

Keď sú všetky zachytené, sú podľa hodnoty:

Ak sa majú zachytiť všetky premenné, ktoré sa majú zachytiť podľa hodnoty, v klauzuli o zachytení postačí iba jedna =. Nasledujúci program to ilustruje:

#include
pomocou namespace std;
int main ()

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

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

Výstup je:

5, 2.3, A, 1

Poznámka: = je odteraz iba na čítanie.

Ak majú byť niektoré premenné zachytené hodnotou a iné odkazom, potom jedna = bude predstavovať všetky kopírované premenné iba na čítanie a zvyšok bude mať znak &, ako ukazuje nasledujúci program:

#include
pomocou namespace std;
int main ()

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

ch = 'B'; bl = false;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
návrat 0;

Výstup je:

5, 2.3, B, 0

Všimnite si, že = sám musí byť prvým znakom v doložke zachytenia.

Schéma klasického spätného volania s výrazom lambda

Nasledujúci program ukazuje, ako je možné vykonať klasickú schému funkcie spätného volania s výrazom lambda:

#include
pomocou namespace std;
char * výstup;
auto cba = [] (char out [])

výstup = von;
;
void principalFunc (char input [], void (* pt) (char []))

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

void fn ()

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

int main ()

char input [] = "pre funkciu spätného volania";
principalFunc (vstup, cba);
fn ();
cout<návrat 0;

Výstup je:

pre hlavnú funkciu
Teraz
pre funkciu spätného volania

Pripomeňme, že keď je definícia výrazu lambda priradená premennej v globálnom rozsahu, jej telo funkcie môže vidieť globálne premenné bez použitia doložky o zachytení.

Typ s koncovým návratom

Návratový typ výrazu lambda je automatický, čo znamená, že kompilátor určuje návratový typ z návratového výrazu (ak je prítomný). Ak programátor chce skutočne označiť návratový typ, urobí to ako v nasledujúcom programe:

#include
pomocou namespace std;
auto fn = [] (int param) -> int

int odpoveď = param + 3;
spätná odpoveď;
;
int main ()

automatická premenná = fn (2);
cout << variab << '\n';
návrat 0;

Výstup je 5. Za zoznamom parametrov sa napíše operátor šípky. Nasleduje návratový typ (v tomto prípade int).

Uzavretie

Zvážte nasledujúci segment kódu:

štruktúra Cla

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

Cla je názov triedy struct.  Obj1 a obj2 sú dva objekty, ktoré budú vytvorené z triedy štruktúr. Lambda expresia je podobná v implementácii. Definícia funkcie lambda je druhom triedy. Keď sa zavolá (vyvolá) funkcia lambda, objekt sa vytvorí z jeho definície. Tento objekt sa nazýva uzáver. Očakáva sa, že práve uzávierka urobí prácu, ktorú bude lambda robiť.

Pri kódovaní výrazu lambda ako vyššie uvedená štruktúra však budú obj1 a obj2 nahradené argumentmi zodpovedajúcich parametrov. Nasledujúci program to ilustruje:

#include
pomocou namespace std;
auto fn = [] (int param1, int param2)

int odpoveď = param1 + param2;
spätná odpoveď;
(2, 3);
int main ()

auto var = fn;
cout << var << '\n';
návrat 0;

Výstup je 5. Argumenty sú 2 a 3 v zátvorkách. Upozorňujeme, že volanie funkcie výrazu lambda, fn, neberie žiadny argument, pretože argumenty už boli kódované na konci definície funkcie lambda.

Záver

Výraz lambda je anonymná funkcia. Skladá sa z dvoch častí: triedy a objektu. Jeho definícia je akousi triedou. Pri volaní výrazu sa z definície vytvorí objekt. Tento objekt sa nazýva uzáver. Očakáva sa, že práve uzávierka urobí prácu, ktorú bude lambda robiť.

Aby výraz lambda dostal premennú z rozsahu vonkajšej funkcie, potrebuje do svojho tela funkcie neprázdnu klauzulu zachytenia.

Hry Ako nainštalovať League Of Legends na Ubuntu 14.04
Ako nainštalovať League Of Legends na Ubuntu 14.04
Ak ste fanúšikom League of Legends, potom je to pre vás príležitosť otestovať spustenie League of Legends. Upozorňujeme, že program PlayOnLinux podpor...
Hry Nainštalujte si najnovšiu strategickú hru OpenRA na Ubuntu Linux
Nainštalujte si najnovšiu strategickú hru OpenRA na Ubuntu Linux
OpenRA je herný engine Libre / Free Real Time Strategy, ktorý obnovuje rané hry z Westwoodu, ako napríklad klasické Command & Conquer: Red Alert. Dist...
Hry Nainštalujte si najnovší Dolphin Emulator pre Gamecube a Wii na Linuxe
Nainštalujte si najnovší Dolphin Emulator pre Gamecube a Wii na Linuxe
Emulátor Dolphin vám umožní hrať vybrané hry Gamecube a Wii na osobných počítačoch Linux (PC). Emulátor Dolphin, ktorý je voľne dostupným emulátorom ...