Ламбда изрази у Ц ++

Lambda Expressions C



Зашто Ламбда израз?

Узмите у обзир следећу изјаву:

интмиИнт= 52;

Овде је миИнт идентификатор, вредност. 52 је дословно, прва вредност. Данас је могуће посебно кодирати функцију и поставити је у положај 52. Таква функција се назива ламбда израз. Узмите у обзир и следећи кратки програм:







#инцлуде

Користећи именски просторсати;

интфн(инткроз)

{

интодговор=кроз+ 3;

повратакодговор;

}


интглавни()

{

фн(5);



повратак 0;

}

Данас је могуће посебно кодирати функцију и поставити је у позицију аргумента 5, позива функције, фн (5). Таква функција се назива ламбда израз. Ламбда израз (функција) у том положају је прва вредност.



Било који литерал осим литералног низа је прва вредност. Ламбда израз је дизајн посебне функције који би се уклопио као дословни код. То је анонимна (неименована) функција. Овај чланак објашњава нови примарни израз Ц ++, назван ламбда израз. Основно знање Ц ++ је услов за разумевање овог чланка.



Садржај чланка

Илустрација ламбда израза

У следећем програму је променљивој додељена функција која је ламбда израз:





#инцлуде

Користећи именски просторсати;

аутофн= [](интзауставити)

{

интодговор=зауставити+ 3;

повратакодговор;

};


интглавни()

{

аутовариаб=фн(2);

цена <<вариаб<< ' н';


повратак 0;

}

Излаз је:

5

Изван функције маин () налази се променљива, фн. Његов тип је ауто. Ауто у овој ситуацији значи да је стварни тип, као што је инт или флоат, одређен десним операндом оператора додељивања (=). Десно од оператора доделе је ламбда израз. Ламбда израз је функција без претходног типа повратка. Обратите пажњу на употребу и положај углатих заграда, []. Функција враћа 5, инт, који ће одредити тип за фн.



У функцији маин () постоји наредба:

аутовариаб=фн(2);

То значи да фн изван маин () завршава као идентификатор функције. Његови имплицитни параметри су они ламбда израза. Тип за вариаб је ауто.

Имајте на уму да се ламбда израз завршава тачком -зарезом, баш као што се дефиниција класе или структуре завршава тачком -зарезом.

У следећем програму, функција, која је ламбда израз који враћа вредност 5, аргумент је другој функцији:

#инцлуде

Користећи именски просторсати;

празнинаотхерфн(интно1,инт (*птр)(инт))

{

интно2= (*птр)(2);

цена <<но1<< '' <<но2<< ' н';

}


интглавни()

{

отхерфн(4,[](интзауставити)

{

интодговор=зауставити+ 3;

повратакодговор;

});


повратак 0;
}

Излаз је:

Четири, пет

Овде постоје две функције, ламбда израз и функција отхерфн (). Ламбда израз је други аргумент отхерфн (), који се позива у маин (). Имајте на уму да се ламбда функција (израз) не завршава тачком-зарезом у овом позиву јер је овде реч о аргументу (а не о самосталној функцији).

Параметар ламбда функције у дефиницији функције отхерфн () је показивач на функцију. Показивач има назив, птр. Име, птр, користи се у дефиницији отхерфн () за позивање ламбда функције.

Изјава,

интно2= (*птр)(2);

У дефиницији отхерфн (), позива ламбда функцију са аргументом 2. Повратна вредност позива, '(*птр) (2)' из ламбда функције, додељује се но2.

Горњи програм такође показује како се ламбда функција може користити у шеми функција повратног позива Ц ++.

Делови ламбда израза

Делови типичне ламбда функције су следећи:

[] () {}
  • [] је клаузула хватања. Може имати ставке.
  • () служи за листу параметара.
  • {} је за тело функције. Ако функција стоји сама, онда би требало да се заврши тачком и зарезом.

Хвата

Дефиниција ламбда функције може се доделити променљивој или користити као аргумент за други позив функције. Дефиниција за такав позив функције треба да има као параметар показивач на функцију, који одговара дефиницији ламбда функције.

Дефиниција ламбда функције се разликује од дефиниције нормалне функције. Може се доделити променљивој у глобалном опсегу; ова функција додељена променљивој се такође може кодирати унутар друге функције. Када се додели променљивој глобалног опсега, њено тело може видети друге променљиве у глобалном опсегу. Када је додељена променљивој унутар нормалне дефиниције функције, њено тело може видети друге променљиве у опсегу функције само уз помоћ клаузуле хватања, [].

Клаузула хватања [], позната и као ламбда-уводник, дозвољава слање променљивих из околног (функције) опсега у тело функције ламбда израза. Речено је да тело функције ламбда израза хвата променљиву када прими објекат. Без клаузе клаузуле [], променљива се не може послати из околног опсега у тело функције ламбда израза. Следећи програм то илуструје, са опсегом функције маин (), као околним опсегом:

#инцлуде

Користећи именски просторсати;

интглавни()

{

интид= 5;


аутофн= [ид]()

{

цена <<ид<< ' н';

};

фн();


повратак 0;

}

Излаз је 5 . Без имена, ид, унутар [], ламбда израз не би видео променљиви ид опсега функције маин ().

Снимање према референци

Горњи пример употребе клаузуле хватања је хватање по вредности (погледајте детаље испод). Приликом хватања референцом, локација (складиште) променљиве, нпр. Ид изнад, околног опсега, постаје доступна унутар тела ламбда функције. Дакле, промена вредности променљиве унутар тела ламбда функције ће променити вредност те исте променљиве у околном опсегу. Свакој променљивој која се понавља у клаузули хватања претходи амперсанд (&) да би се то постигло. Следећи програм то илуструје:

#инцлуде

Користећи именски просторсати;

интглавни()

{

интид= 5; пловакфт= 2.3; цхарцх= 'ДО';

аутофн= [&ид,&фт,&цх]()

{

ид= 6;фт= 3.4;цх= 'Б';

};

фн();

цена <<ид<< ',' <<фт<< ',' <<цх<< ' н';

повратак 0;

}

Излаз је:

6, 3.4, Б.

Потврђујући да су имена променљивих унутар тела функције ламбда израза за исте променљиве изван ламбда израза.

Снимање према вредности

Приликом хватања по вредности, копија локације променљиве, њеног опсега, доступна је унутар тела ламбда функције. Иако је променљива унутар тела ламбда функције копија, њена вредност се тренутно не може променити унутар тела. Да би се постигло хватање по вредности, свакој променљивој која се понавља у клаузули хватања не претходи ништа. Следећи програм то илуструје:

#инцлуде

Користећи именски просторсати;

интглавни()

{

интид= 5; пловакфт= 2.3; цхарцх= 'ДО';

аутофн= [ид, фт, цх]()

{

// ид = 6; фт = 3,4; цх = 'Б';

цена <<ид<< ',' <<фт<< ',' <<цх<< ' н';

};

фн();

ид= 6;фт= 3.4;цх= 'Б';

цена <<ид<< ',' <<фт<< ',' <<цх<< ' н';

повратак 0;

}

Излаз је:

5, 2.3, А.

6, 3.4, Б.

Ако се индикатор коментара уклони, програм се неће компајлирати. Компајлер ће издати поруку о грешци да се променљиве унутар дефиниције ламбда израза тела функције не могу променити. Иако се променљиве не могу променити унутар ламбда функције, оне се могу променити изван ламбда функције, као што показује излаз горе наведеног програма.

Мешање снимака

Снимање према референци и хватање по вредности може се мешати, као што показује следећи програм:

#инцлуде

Користећи именски просторсати;

интглавни()

{

интид= 5; пловакфт= 2.3; цхарцх= 'ДО'; боолбл= истина;


аутофн= [ид, фт,&цх,&бл]()

{

цх= 'Б';бл= лажно;

цена <<ид<< ',' <<фт<< ',' <<цх<< ',' <<бл<< ' н';

};

фн();


повратак 0;

}

Излаз је:

5, 2.3, Б, 0

Када се све ухвати, референца је:

Ако су све варијабле које се хватају ухваћене референцом, тада ће само једна & бити довољна у клаузули хватања. Следећи програм то илуструје:

#инцлуде

Користећи именски просторсати;

интглавни()

{

интид= 5; пловакфт= 2.3; цхарцх= 'ДО'; боолбл= истина;


аутофн= [&]()

{

ид= 6;фт= 3.4;цх= 'Б';бл= лажно;

};

фн();

цена <<ид<< ',' <<фт<< ',' <<цх<< ',' <<бл<< ' н';


повратак 0;

}

Излаз је:

6, 3.4, Б, 0

Ако се неке променљиве хватају по референци, а друге по вредности, онда ће једна & представљати све референце, а осталима неће ништа претходити, како показује следећи програм:

Користећи именски просторсати;

интглавни()

{

интид= 5; пловакфт= 2.3; цхарцх= 'ДО'; боолбл= истина;


аутофн= [&, ид, фт]()

{

цх= 'Б';бл= лажно;

цена <<ид<< ',' <<фт<< ',' <<цх<< ',' <<бл<< ' н';

};

фн();


повратак 0;

}

Излаз је:

5, 2.3, Б, 0

Имајте на уму да & сам (тј. & Иза кога не следи идентификатор) мора бити први знак у клаузули хватања.

Када се све ухвати, вреди:

Ако се све променљиве које се хватају хватају по вредности, тада ће само једна = бити довољна у клаузули хватања. Следећи програм то илуструје:

#инцлуде

Користећи именски просторсати;

интглавни()
{

интид= 5; пловакфт= 2.3; цхарцх= 'ДО'; боолбл= истина;


аутофн= [=]()

{

цена <<ид<< ',' <<фт<< ',' <<цх<< ',' <<бл<< ' н';

};

фн();


повратак 0;


}

Излаз је:

5, 2.3, А, 1

Белешка : = је само за читање, од сада.

Ако се неке променљиве хватају по вредности, а друге по референци, онда ће једна = представљати све променљиве само за читање, а остале ће имати &, као што показује следећи програм:

#инцлуде

Користећи именски просторсати;

интглавни()

{

интид= 5; пловакфт= 2.3; цхарцх= 'ДО'; боолбл= истина;


аутофн= [=,&цх,&бл]()

{

цх= 'Б';бл= лажно;

цена <<ид<< ',' <<фт<< ',' <<цх<< ',' <<бл<< ' н';

};

фн();


повратак 0;

}

Излаз је:

5, 2.3, Б, 0

Имајте на уму да = само мора бити први знак у клаузули хватања.

Класична шема функција повратног позива са ламбда изразом

Следећи програм приказује како се класична шема функција повратног позива може извести помоћу ламбда израза:

#инцлуде

Користећи именски просторсати;

цхар *излаз;


аутоцба= [](цхароут[])

{

излаз=оут;

};



празнинамаинФунц(цхарулазни[],празнина (*за)(цхар[]))

{

(*за)(улазни);

цена<<'за главну функцију'<<' н';

}


празнинафн()

{

цена<<'Сада'<<' н';

}


интглавни()

{

цхарулазни[] = 'за функцију повратног позива';

маинФунц(улаз, цба);

фн();

цена<<излаз<<' н';



повратак 0;

}

Излаз је:

за главну функцију

Сада

за функцију повратног позива

Подсјетимо се да када је дефиниција ламбда израза додијељена варијабли у глобалном опсегу, њено тијело функције може видјети глобалне варијабле без употребе клаузуле хватања.

Траилинг-ретурн-типе

Врста повратка ламбда израза је ауто, што значи да компајлер одређује тип повратка из повратног израза (ако постоји). Ако програмер заиста жели да наведе врсту повратка, онда ће то учинити као у следећем програму:

#инцлуде

Користећи именски просторсати;

аутофн= [](интзауставити) -> инт

{

интодговор=зауставити+ 3;

повратакодговор;

};


интглавни()

{

аутовариаб=фн(2);

цена <<вариаб<< ' н';


повратак 0;

}

Излаз је 5. Након листе параметара уписује се оператор стрелице. Након тога следи тип повратка (инт у овом случају).

Затварање

Размотрите следећи сегмент кода:

струцтЦла

{

интид= 5;

цхарцх= 'до';

}обј1, обј2;

Овде је Цла име класе струцт. Обј1 и обј2 су два објекта која ће бити изведена из класе струцт. Ламбда израз је сличан у имплементацији. Дефиниција ламбда функције је нека врста класе. Када се ламбда функција позове (позове), објекат се инстанцира из његове дефиниције. Овај објекат се назива затварање. Затварање обавља посао од којег се очекује да ламбда уради.

Међутим, кодирање ламбда израза попут горње структуре имаће обј1 и обј2 замењене аргументима одговарајућих параметара. Следећи програм то илуструје:

#инцлуде

Користећи именски просторсати;

аутофн= [](интпарам1,интпарам2)

{

интодговор=парам1+парам2;

повратакодговор;

} (2,3);


интглавни()

{

аутогде=фн;

цена <<где<< ' н';


повратак 0;

}

Излаз је 5. Аргументи су 2 и 3 у заградама. Имајте на уму да позив функције ламбда израза, фн, не узима никакав аргумент јер су аргументи већ кодирани на крају дефиниције ламбда функције.

Закључак

Ламбда израз је анонимна функција. Он се састоји из два дела: класе и објекта. Његова дефиниција је нека врста класе. Када се израз позове, из дефиниције се формира објекат. Овај објекат се назива затварање. Затварање обавља посао од којег се очекује да ламбда уради.

Да би ламбда израз примио променљиву из спољног опсега функције, потребна му је непразна клаузула хватања у тело функције.