Защо Lambda Expression?
Обмислете следното твърдение:
int myInt = 52;Тук myInt е идентификатор, стойност. 52 е буквал, първо значение. Днес е възможно да се кодира функция специално и да се постави в положение 52. Такава функция се нарича ламбда израз. Обмислете и следната кратка програма:
#includeизползване на пространство от имена std;
int fn (int par)
int отговор = par + 3;
връщане отговор;
int main ()
fn (5);
връщане 0;
Днес е възможно да се кодира функция специално и да се постави в позицията на аргумента 5, на извикването на функция, fn (5). Такава функция се нарича ламбда израз. Ламбда изразът (функцията) в тази позиция е първо значение.
Всеки литерал, с изключение на низовия литерал, е първа стойност. Ламбда изразът е специален функционален дизайн, който би се побрал като буквал в кода. Това е анонимна (неназована) функция. Тази статия обяснява новия първичен израз на C ++, наречен ламбда израз. Основните познания в C ++ са изискване за разбиране на тази статия.
Съдържание на статията
- Илюстрация на ламбда израз
- Части от Lambda Expression
- Захващания
- Класическа функционална схема за обратно извикване с ламбда-израз
- Типът завършващо връщане
- Закриване
- Заключение
Илюстрация на ламбда израз
В следващата програма функция, която е ламбда израз, се присвоява на променлива:
#includeизползване на пространство от имена std;
автоматично fn = [] (int param)
int отговор = param + 3;
връщане отговор;
;
int main ()
автоматична променлива = fn (2);
Cout << variab << '\n';
връщане 0;
Резултатът е:
5Извън функцията main () има променливата fn. Типът му е автоматичен. Авто в тази ситуация означава, че действителният тип, като int или float, се определя от десния операнд на оператора за присвояване (=). Отдясно на оператора за присвояване има ламбда израз. Ламбда израз е функция без предходния тип връщане. Обърнете внимание на използването и позицията на квадратните скоби, []. Функцията връща 5, int, което ще определи типа за fn.
Във функцията main () има изявлението:
автоматична променлива = fn (2);Това означава, че fn извън main () завършва като идентификатор на функция. Нейните неявни параметри са тези на ламбда израза. Типът за variab е автоматично.
Обърнете внимание, че ламбда изразът завършва с точка и запетая, точно както дефиницията на класа или структурата, завършва с точка и запетая.
В следващата програма функция, която е ламбда израз, връщащ стойността на 5, е аргумент на друга функция:
#includeизползване на пространство от имена std;
void otherfn (int no1, int (* ptr) (int))
int no2 = (* ptr) (2);
Cout << no1 << " << no2 << '\n';
int main ()
otherfn (4, [] (int param)
int отговор = param + 3;
връщане отговор;
);
връщане 0;
Резултатът е:
4 5Тук има две функции, ламбда изразът и функцията otherfn (). Ламбда изразът е вторият аргумент на otherfn (), извикан в main (). Имайте предвид, че ламбда функцията (изразът) не завършва с точка и запетая в това извикване, защото тук тя е аргумент (а не самостоятелна функция).
Параметърът на ламбда функция в дефиницията на функцията otherfn () е указател към функция. Показалецът има името, ptr. Името, ptr, се използва в дефиницията otherfn () за извикване на ламбда функцията.
Изявлението,
int no2 = (* ptr) (2);В дефиницията otherfn () извиква функцията ламбда с аргумент 2. Връщаната стойност на повикването, "(* ptr) (2)" от ламбда функцията, се присвоява на no2.
Горната програма също така показва как ламбда функцията може да се използва в схемата на функцията за обратно извикване на C ++.
Части от Lambda Expression
Частите на типична ламбда функция са както следва:
[] ()- [] е клаузата за улавяне. Може да има елементи.
- () е за списъка с параметри.
- е за тялото на функцията. Ако функцията е самостоятелна, тя трябва да завършва с точка и запетая.
Захващания
Дефиницията на ламбда функция може да бъде присвоена на променлива или използвана като аргумент на различно извикване на функция. Дефиницията за такова извикване на функция трябва да има като параметър, указател към функция, съответстваща на дефиницията на ламбда функция.
Дефиницията на ламбда функция се различава от нормалната дефиниция на функцията. Той може да бъде присвоен на променлива в глобалния обхват; тази функция, присвоена на променлива, може да бъде кодирана и в друга функция. Когато е присвоено на глобална променлива на обхвата, нейното тяло може да вижда други променливи в глобалния обхват. Когато е присвоена на променлива в рамките на нормална дефиниция на функция, нейното тяло може да вижда други променливи в обхвата на функцията само с помощта на клаузата за улавяне, [].
Клаузата за улавяне [], известна също като ламбда-въвеждащ, позволява изпращането на променливи от обкръжаващия (функция) обхват в тялото на функцията на ламбда израза. Казва се, че функцията на тялото на ламбда израза улавя променливата, когато получи обекта. Без клаузата за улавяне [] променлива не може да бъде изпратена от околния обхват в тялото на функцията на ламбда израза. Следващата програма илюстрира това с обхвата на функцията main () като обхват на околната среда:
#includeизползване на пространство от имена std;
int main ()
int id = 5;
автоматично fn = [id] ()
Cout << id << '\n';
;
fn ();
връщане 0;
Изходът е 5. Без името, id, вътре [], ламбда изразът не би видял променливата id на обхвата на функцията main ().
Заснемане чрез справка
Горният пример за използване на клаузата за улавяне е улавяне по стойност (вижте подробности по-долу). При улавяне чрез препратка, местоположението (съхранението) на променливата, напр.ж., id по-горе, от обхвата на околността, се предоставя в тялото на функцията на ламбда функцията. Така че, промяната на стойността на променливата в тялото на ламбда функцията ще промени стойността на същата тази променлива в околния обхват. Всяка променлива, повторена в клаузата за улавяне, се предшества от амперсанда (&), за да се постигне това. Следващата програма илюстрира това:
#includeизползване на пространство от имена std;
int main ()
int id = 5; float ft = 2.3; char ch = 'A';
автоматично fn = [& id, & ft, & ch] ()
id = 6; ft = 3.4; ch = 'B';
;
fn ();
Cout << id << ", " << ft << ", " << ch << '\n';
връщане 0;
Резултатът е:
6, 3.4, БПотвърждаване, че имената на променливите в тялото на функцията на ламбда израза са за същите променливи извън ламбда израза.
Заснемане по стойност
При улавяне по стойност, копие на местоположението на променливата, на обкръжаващия обхват, се предоставя в тялото на функцията на ламбда функцията. Въпреки че променливата вътре в тялото на ламбда функцията е копие, нейната стойност не може да бъде променена вътре в тялото към момента. За да се постигне улавяне по стойност, всяка променлива, повторена в клаузата за улавяне, не се предшества от нищо. Следващата програма илюстрира това:
#includeизползване на пространство от имена std;
int main ()
int id = 5; float ft = 2.3; char ch = 'A';
автоматично 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';
връщане 0;
Резултатът е:
5, 2.3, А6, 3.4, Б
Ако индикаторът за коментар бъде премахнат, програмата няма да се компилира. Компилаторът ще издаде съобщение за грешка, че променливите в дефиницията на функцията на тялото на ламбда израза не могат да бъдат променяни. Въпреки че променливите не могат да се променят вътре в ламбда функцията, те могат да се променят извън ламбда функцията, както показва изходът на горната програма.
Смесване на улавяния
Заснемането чрез справка и улавянето по стойност може да се смесва, както показва следната програма:
#includeизползване на пространство от имена std;
int main ()
int id = 5; float ft = 2.3; char ch = 'A'; bool bl = вярно;
автоматично fn = [id, ft, & ch, & bl] ()
ch = 'B'; bl = невярно;
Cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
връщане 0;
Резултатът е:
5, 2.3, В, 0Когато всички са заловени, са по справка:
Ако всички променливи, които трябва да бъдат уловени, са уловени чрез препратка, тогава само една & ще бъде достатъчна в клаузата за улавяне. Следващата програма илюстрира това:
#includeизползване на пространство от имена std;
int main ()
int id = 5; float ft = 2.3; char ch = 'A'; bool bl = вярно;
автоматично fn = [&] ()
id = 6; ft = 3.4; ch = 'B'; bl = невярно;
;
fn ();
Cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
връщане 0;
Резултатът е:
6, 3.4, В, 0Ако някои променливи трябва да бъдат уловени чрез препратка, а други по стойност, тогава една & ще представлява всички препратки, а останалите няма да бъдат предшествани от нищо, както показва следната програма:
използване на пространство от имена std;int main ()
int id = 5; float ft = 2.3; char ch = 'A'; bool bl = вярно;
автоматично fn = [&, id, ft] ()
ch = 'B'; bl = невярно;
Cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
връщане 0;
Резултатът е:
5, 2.3, В, 0Обърнете внимание, че & сам (i.д., & не последвано от идентификатор) трябва да бъде първият знак в клаузата за улавяне.
Когато всички са уловени, са по стойност:
Ако всички променливи, които трябва да бъдат уловени, трябва да бъдат уловени по стойност, тогава само една = ще бъде достатъчна в клаузата за улавяне. Следващата програма илюстрира това:
#includeизползване на пространство от имена std;
int main ()
int id = 5; float ft = 2.3; char ch = 'A'; bool bl = вярно;
автоматично fn = [=] ()
Cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
връщане 0;
Резултатът е:
5, 2.3, А, 1Забележка: = отсега е само за четене.
Ако някои променливи трябва да бъдат уловени по стойност, а други по препратка, тогава една = ще представлява всички копирани променливи само за четене, а останалите ще имат &, както показва следната програма:
#includeизползване на пространство от имена std;
int main ()
int id = 5; float ft = 2.3; char ch = 'A'; bool bl = вярно;
автоматично fn = [=, & ch, & bl] ()
ch = 'B'; bl = невярно;
Cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
връщане 0;
Резултатът е:
5, 2.3, В, 0Имайте предвид, че = сам трябва да е първият символ в клаузата за улавяне.
Класическа функционална схема за обратно извикване с ламбда-израз
Следващата програма показва как може да се направи класическа функция на функцията за обратно извикване с ламбда израза:
#includeизползване на пространство от имена std;
char * изход;
автоматично cba = [] (извеждане на символа [])
изход = изход;
;
void principalFunc (въвеждане на символи [], void (* pt) (char []))
(* pt) (вход);
Cout<<"for principal function"<<'\n';
void fn ()
Cout<<"Now"<<'\n';
int main ()
char input [] = "за функция за обратно извикване";
principalFunc (вход, cba);
fn ();
Cout<