Lambda výrazy v C ++

Lambda Expressions C



Proč Lambda Expression?

Zvažte následující tvrzení:

intmyInt= 52;

Zde je myInt identifikátor, hodnota l. 52 je doslovný, prvočíslo. Dnes je možné speciálně kódovat funkci a dát ji na pozici 52. Takové funkci se říká výraz lambda. Zvažte také následující krátký program:







#zahrnout

použitím jmenný prostorhodiny;

intfn(intpřes)

{

intOdpovědět=přes+ 3;

vrátit seOdpovědět;

}


inthlavní()

{

fn(5);



vrátit se 0;

}

Dnes je možné speciálně kódovat funkci a postavit ji na pozici argumentu 5, volání funkce, fn (5). Taková funkce se nazývá výraz lambda. Výraz lambda (funkce) v této pozici je prvou hodnotou.



Libovolný literál kromě řetězcového literálu je prvou hodnotou. Výraz lambda je návrh speciální funkce, který by se hodil jako doslovný v kódu. Jedná se o anonymní (nepojmenovanou) funkci. Tento článek vysvětluje nový primární výraz C ++, nazývaný výraz lambda. Základní znalost C ++ je podmínkou pro pochopení tohoto článku.



Obsah článku

Ilustrace lambda výrazu

V následujícím programu je proměnné přiřazena funkce, což je výraz lambda:





#zahrnout

použitím jmenný prostorhodiny;

autofn= [](intstop)

{

intOdpovědět=stop+ 3;

vrátit seOdpovědět;

};


inthlavní()

{

autovariab=fn(2);

náklady <<variab<< ' n';


vrátit se 0;

}

Výstupem je:

5

Mimo funkci main () existuje proměnná, fn. Jeho typ je automatický. Auto v této situaci znamená, že skutečný typ, například int nebo float, je určen pravým operandem operátoru přiřazení (=). Vpravo od operátoru přiřazení je výraz lambda. Výraz lambda je funkce bez předchozího návratového typu. Všimněte si použití a umístění hranatých závorek, []. Funkce vrací 5, int, které určí typ pro fn.



Ve funkci main () je prohlášení:

autovariab=fn(2);

To znamená, že fn mimo main () končí jako identifikátor funkce. Jeho implicitní parametry jsou parametry výrazu lambda. Typ pro proměnnou je automatický.

Všimněte si, že výraz lambda končí středníkem, stejně jako definice třídy nebo struktury končí středníkem.

V následujícím programu je funkce, což je výraz lambda vracející hodnotu 5, argumentem pro jinou funkci:

#zahrnout

použitím jmenný prostorhodiny;

prázdnéostatní(intč.1,int (*ptr)(int))

{

intč. 2= (*ptr)(2);

náklady <<č.1<< '' <<č. 2<< ' n';

}


inthlavní()

{

ostatní(4,[](intstop)

{

intOdpovědět=stop+ 3;

vrátit seOdpovědět;

});


vrátit se 0;
}

Výstupem je:

Čtyři pět

Jsou zde dvě funkce, výraz lambda a funkce otherfn (). Výraz lambda je druhým argumentem otherfn (), který se nazývá main (). Všimněte si, že funkce lambda (výraz) nekončí středníkem v tomto volání, protože zde jde o argument (nikoli o samostatnou funkci).

Parametr funkce lambda v definici funkce otherfn () je ukazatelem na funkci. Ukazatel má jméno ptr. Název ptr se v definici otherfn () používá k volání funkce lambda.

Prohlášení,

intč. 2= (*ptr)(2);

V definici otherfn () volá funkci lambda s argumentem 2. Návratová hodnota volání '(*ptr) (2)' z funkce lambda je přiřazena k no2.

Výše uvedený program také ukazuje, jak lze funkci lambda použít ve schématu funkce zpětného volání C ++.

Části Lambda Expression

Části typické funkce lambda jsou následující:

[] () {}
  • [] je doložka o zachycení. Může mít položky.
  • () je pro seznam parametrů.
  • {} je pro tělo funkce. Pokud funkce stojí samostatně, měla by končit středníkem.

Zachycuje

Definici funkce lambda lze přiřadit proměnné nebo použít jako argument pro jiné volání funkce. Definice pro takové volání funkce by měla mít jako parametr, ukazatel na funkci, odpovídající definici funkce lambda.

Definice funkce lambda se liší od definice normální funkce. Lze ji přiřadit proměnné v globálním rozsahu; tato funkce přiřazená k proměnné může být také kódována uvnitř jiné funkce. Když je přiřazen proměnné globálního rozsahu, jeho tělo může vidět další proměnné v globálním oboru. Když je její tělo přiřazeno k proměnné v definici normální funkce, její tělo může vidět další proměnné v rozsahu funkce pouze s pomocí klauzule zachycení, [].

Klauzule zachycení [], známá také jako zavaděč lambda, umožňuje odesílání proměnných z okolního (funkčního) rozsahu do těla funkce výrazu lambda. Tělo funkce výrazu lambda údajně zachycuje proměnnou, když přijímá objekt. Bez klauzule capture [] nelze proměnnou odeslat z okolního rozsahu do těla funkce výrazu lambda. Následující program to ilustruje s rozsahem funkce main () jako okolním rozsahem:

#zahrnout

použitím jmenný prostorhodiny;

inthlavní()

{

intid= 5;


autofn= [id]()

{

náklady <<id<< ' n';

};

fn();


vrátit se 0;

}

Výstup je 5 . Bez názvu, id, uvnitř [] by výraz lambda neviděl proměnnou id rozsahu funkce main ().

Zachycení referencí

Výše uvedené příklad použití klauzule pro zachycení je zachycení podle hodnoty (viz podrobnosti níže). Při zachycení pomocí odkazu je v těle funkce lambda k dispozici umístění (úložiště) proměnné, např. Id výše, okolního rozsahu. Takže změna hodnoty proměnné uvnitř těla funkce lambda změní hodnotu stejné proměnné v okolním rozsahu. Aby se toho dosáhlo, každé proměnné opakované v klauzuli zachycení předchází znak ampersand (&). Následující program to ilustruje:

#zahrnout

použitím jmenný prostorhodiny;

inthlavní()

{

intid= 5; plovákft= 2.3; charch= 'NA';

autofn= [&id,&ft,&ch]()

{

id= 6;ft= 3.4;ch= 'B';

};

fn();

náklady <<id<< ',' <<ft<< ',' <<ch<< ' n';

vrátit se 0;

}

Výstupem je:

6, 3,4, B

Potvrzení, že názvy proměnných uvnitř těla funkce výrazu lambda jsou pro stejné proměnné mimo výraz lambda.

Zachycení podle hodnoty

Při zachycení podle hodnoty je v těle funkce lambda k dispozici kopie umístění proměnné okolního rozsahu. Ačkoli je proměnná uvnitř těla funkce lambda kopie, její hodnotu nelze v těle nyní změnit. Aby bylo dosaženo zachycení podle hodnoty, před každou proměnnou opakovanou v klauzuli pro zachycení nic nepředchází. Následující program to ilustruje:

#zahrnout

použitím jmenný prostorhodiny;

inthlavní()

{

intid= 5; plovákft= 2.3; charch= 'NA';

autofn= [id, ft, ch]()

{

// id = 6; ft = 3,4; ch = 'B';

náklady <<id<< ',' <<ft<< ',' <<ch<< ' n';

};

fn();

id= 6;ft= 3.4;ch= 'B';

náklady <<id<< ',' <<ft<< ',' <<ch<< ' n';

vrátit se 0;

}

Výstupem je:

5, 2,3, A

6, 3,4, B

Pokud je indikátor komentáře odstraněn, program nebude kompilovat. Kompilátor vydá chybovou zprávu, že proměnné uvnitř definice výrazu lambda v těle funkce nelze změnit. Ačkoli proměnné nelze měnit uvnitř funkce lambda, lze je změnit mimo funkci lambda, jak ukazuje výstup výše uvedeného programu.

Míchání zachycení

Zachycení podle odkazu a zachycení podle hodnoty lze kombinovat, jak ukazuje následující program:

#zahrnout

použitím jmenný prostorhodiny;

inthlavní()

{

intid= 5; plovákft= 2.3; charch= 'NA'; boolbl= skutečný;


autofn= [id, ft,&ch,&bl]()

{

ch= 'B';bl= Nepravdivé;

náklady <<id<< ',' <<ft<< ',' <<ch<< ',' <<bl<< ' n';

};

fn();


vrátit se 0;

}

Výstupem je:

5, 2,3, B, 0

Když jsou všechny zachyceny, jsou podle odkazu:

Pokud jsou všechny proměnné, které mají být zachyceny, zachyceny referencí, pak v klauzuli o zachycení postačí pouze jedna &. Následující program to ilustruje:

#zahrnout

použitím jmenný prostorhodiny;

inthlavní()

{

intid= 5; plovákft= 2.3; charch= 'NA'; boolbl= skutečný;


autofn= [&]()

{

id= 6;ft= 3.4;ch= 'B';bl= Nepravdivé;

};

fn();

náklady <<id<< ',' <<ft<< ',' <<ch<< ',' <<bl<< ' n';


vrátit se 0;

}

Výstupem je:

6, 3,4, B, 0

Pokud mají být některé proměnné zachyceny odkazem a jiné hodnotou, pak jedna & bude představovat všechny reference a ostatním nebude nic předcházet, jak ukazuje následující program:

použitím jmenný prostorhodiny;

inthlavní()

{

intid= 5; plovákft= 2.3; charch= 'NA'; boolbl= skutečný;


autofn= [&, id, ft]()

{

ch= 'B';bl= Nepravdivé;

náklady <<id<< ',' <<ft<< ',' <<ch<< ',' <<bl<< ' n';

};

fn();


vrátit se 0;

}

Výstupem je:

5, 2,3, B, 0

Všimněte si, že & osamocený (tj. & Nenásledovaný identifikátorem) musí být první znak v klauzuli o zachycení.

Když jsou všechny zachyceny, jsou podle hodnoty:

Pokud mají být všechny proměnné, které mají být zachyceny, zachyceny podle hodnoty, pak v klauzuli pro zachycení postačí pouze jedna =. Následující program to ilustruje:

#zahrnout

použitím jmenný prostorhodiny;

inthlavní()
{

intid= 5; plovákft= 2.3; charch= 'NA'; boolbl= skutečný;


autofn= [=]()

{

náklady <<id<< ',' <<ft<< ',' <<ch<< ',' <<bl<< ' n';

};

fn();


vrátit se 0;


}

Výstupem je:

5, 2,3, A, 1

Poznámka : = je zatím jen pro čtení.

Pokud mají být některé proměnné zachyceny podle hodnoty a jiné podle odkazu, pak jedna = bude představovat všechny kopírované proměnné pouze pro čtení a ostatní budou mít &, jak ukazuje následující program:

#zahrnout

použitím jmenný prostorhodiny;

inthlavní()

{

intid= 5; plovákft= 2.3; charch= 'NA'; boolbl= skutečný;


autofn= [=,&ch,&bl]()

{

ch= 'B';bl= Nepravdivé;

náklady <<id<< ',' <<ft<< ',' <<ch<< ',' <<bl<< ' n';

};

fn();


vrátit se 0;

}

Výstupem je:

5, 2,3, B, 0

Všimněte si, že = osamocený musí být první znak v klauzuli zachycení.

Klasické schéma zpětného volání s výrazem lambda

Následující program ukazuje, jak lze pomocí výrazu lambda provést klasické schéma funkce zpětného volání:

#zahrnout

použitím jmenný prostorhodiny;

char *výstup;


autocba= [](charven[])

{

výstup=ven;

};



prázdnémainFunc(charvstup[],prázdné (*pro)(char[]))

{

(*pro)(vstup);

náklady<<'pro hlavní funkci'<<' n';

}


prázdnéfn()

{

náklady<<'Nyní'<<' n';

}


inthlavní()

{

charvstup[] = 'pro funkci zpětného volání';

mainFunc(vstup, cba);

fn();

náklady<<výstup<<' n';



vrátit se 0;

}

Výstupem je:

pro hlavní funkci

Nyní

pro funkci zpětného volání

Připomeňme si, že když je definici výrazu lambda přiřazena k proměnné v globálním rozsahu, její tělo funkce může vidět globální proměnné bez použití klauzule pro zachycení.

Koncový návratový typ

Návratový typ výrazu lambda je automatický, což znamená, že kompilátor určuje návratový typ z návratového výrazu (je -li přítomen). Pokud chce programátor skutečně uvést typ návratu, udělá to jako v následujícím programu:

#zahrnout

použitím jmenný prostorhodiny;

autofn= [](intstop) -> int

{

intOdpovědět=stop+ 3;

vrátit seOdpovědět;

};


inthlavní()

{

autovariab=fn(2);

náklady <<variab<< ' n';


vrátit se 0;

}

Výstup je 5. Po seznamu parametrů se zadá operátor šipky. Následuje návratový typ (v tomto případě int).

Uzavření

Zvažte následující segment kódu:

strukturaCla

{

intid= 5;

charch= 'na';

}obj1, obj2;

Zde je Cla název třídy struct. Obj1 a obj2 jsou dva objekty, které budou vytvořeny pomocí instance ze třídy struct. Lambda výraz je implementací podobný. Definice funkce lambda je druh třídy. Když se zavolá (vyvolá) funkce lambda, vytvoří se instanci objektu z jeho definice. Tento objekt se nazývá uzavření. Je to uzavření, které dělá práci, od které se očekává, že bude dělat lambda.

Při kódování výrazu lambda jako výše uvedené struktury však budou obj1 a obj2 nahrazeny argumenty odpovídajících parametrů. Následující program to ilustruje:

#zahrnout

použitím jmenný prostorhodiny;

autofn= [](intparam1,intparam2)

{

intOdpovědět=param1+param2;

vrátit seOdpovědět;

} (2,3);


inthlavní()

{

autokde=fn;

náklady <<kde<< ' n';


vrátit se 0;

}

Výstup je 5. Argumenty jsou 2 a 3 v závorkách. Volání funkce výrazu lambda fn nepřijímá žádný argument, protože argumenty již byly kódovány na konci definice funkce lambda.

Závěr

Výraz lambda je anonymní funkce. Má dvě části: třídu a objekt. Jeho definice je druh třídy. Při volání výrazu se z definice vytvoří objekt. Tento objekt se nazývá uzavření. Je to uzavření, které dělá práci, od které se očekává, že bude dělat lambda.

Aby výraz lambda přijímal proměnnou z vnějšího rozsahu funkcí, potřebuje do těla funkce neprázdnou klauzuli zachycení.