Ламбда изрази в C ++

Lambda Expressions C



Защо Lambda Expression?

Помислете за следното твърдение:

intmyInt= 52;

Тук myInt е идентификатор, стойност. 52 е буквално, първа стойност. Днес е възможно да се кодира функция специално и да се постави в позиция 52. Такава функция се нарича ламбда израз. Помислете и за следната кратка програма:







#включва

използвайки пространство на именатачаса;

intfn(intпрез)

{

intотговор=през+ 3;

връщанеотговор;

}


intглавен()

{

fn(5);



връщане 0;

}

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



Всеки литерал с изключение на низовия литерал е първа стойност. Ламбда изразът е специален функционален дизайн, който би се вписал като литерал в кода. Това е анонимна (неназована) функция. Тази статия обяснява новия първичен C ++ израз, наречен ламбда израз. Основните познания в C ++ са изискване за разбиране на тази статия.



Съдържание на статията

Илюстрация на ламбда израз

В следната програма функция, която е ламбда израз, се присвоява на променлива:





#включва

използвайки пространство на именатачаса;

Автоматиченfn= [](intСпри се)

{

intотговор=Спри се+ 3;

връщанеотговор;

};


intглавен()

{

Автоматиченвариаб=fn(2);

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


връщане 0;

}

Изходът е:

5

Извън функцията main () има променливата, fn. Неговият тип е автоматичен. Auto в тази ситуация означава, че действителният тип, например int или float, се определя от десния операнд на оператора за присвояване (=). Вдясно от оператора за присвояване е ламбда израз. Ламбда изразът е функция без предходния тип връщане. Обърнете внимание на използването и позицията на квадратните скоби, []. Функцията връща 5, int, което ще определи типа за fn.



Във функцията main () има израза:

Автоматиченвариаб=fn(2);

Това означава, че fn извън main () завършва като идентификатор за функция. Неговите неявни параметри са тези на ламбда израза. Типът за variab е auto.

Обърнете внимание, че ламбда изразът завършва с точка и запетая, точно както определението за клас или структура, завършва с точка и запетая.

В следната програма функция, която е ламбда израз, връщаща стойността на 5, е аргумент към друга функция:

#включва

използвайки пространство на именатачаса;

невалиденotherfn(intне1,int (*птр)(int))

{

int№2= (*птр)(2);

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

}


intглавен()

{

otherfn(4,[](intСпри се)

{

intотговор=Спри се+ 3;

връщанеотговор;

});


връщане 0;
}

Изходът е:

Четири пет

Тук има две функции, ламбда изразът и функцията otherfn (). Ламбда изразът е вторият аргумент на otherfn (), извикан в main (). Обърнете внимание, че ламбда функцията (израз) не завършва с точка и запетая в това извикване, защото тук това е аргумент (а не самостоятелна функция).

Параметърът на ламбда функцията в дефиницията на функцията otherfn () е указател към функция. Указателят има името, ptr. Името, ptr, се използва в дефиницията otherfn () за извикване на ламбда функцията.

Изявлението,

int№2= (*птр)(2);

В дефиницията otherfn (), тя извиква ламбда функцията с аргумент 2. Връщаната стойност на извикването „(*ptr) (2)“ от ламбда функцията се присвоява на no2.

Горната програма също така показва как ламбда функцията може да се използва в схемата на функцията за обратно повикване на C ++.

Части от ламбда израза

Частите на типичната ламбда функция са както следва:

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

Захваща

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

Дефиницията на ламбда функция е различна от дефиницията на нормалната функция. Тя може да бъде присвоена на променлива в глобалния обхват; тази функция, присвоена на променлива, също може да бъде кодирана в друга функция. Когато е присвоена на променлива за глобален обхват, нейното тяло може да вижда други променливи в глобалния обхват. Когато е присвоена на променлива в дефиницията на нормална функция, нейното тяло може да вижда други променливи в обхвата на функцията само с помощта на клаузата за улавяне, [].

Клаузата за улавяне [], известна още като ламбда-въвеждащ, позволява да се изпращат променливи от околния (функция) обхват в тялото на функцията на ламбда израза. Казва се, че тялото на функцията на ламбда израза улавя променливата, когато получи обекта. Без клаузата за улавяне [] променлива не може да бъде изпратена от околния обхват в тялото на функцията на ламбда израза. Следващата програма илюстрира това, с обхвата на функцията main (), като околния обхват:

#включва

използвайки пространство на именатачаса;

intглавен()

{

intдокумент за самоличност= 5;


Автоматиченfn= [документ за самоличност]()

{

цена <<документ за самоличност<< 'н';

};

fn();


връщане 0;

}

Изходът е 5 . Без името, id, вътре [], ламбда изразът не би видял променливия id на обхвата на функцията main ().

Заснемане по справка

Горният пример за използване на клаузата за улавяне е улавяне по стойност (вижте подробности по -долу). При улавяне чрез препратка местоположението (съхранението) на променливата, напр. Id по -горе, на обкръжаващия обхват, става достъпно вътре в тялото на ламбда функцията. Така че, промяната на стойността на променливата в тялото на ламбда функцията ще промени стойността на същата тази променлива в околния обхват. Всяка променлива, повторена в клаузата за улавяне, се предхожда от амперсанда (&), за да се постигне това. Следната програма илюстрира това:

#включва

използвайки пространство на именатачаса;

intглавен()

{

intдокумент за самоличност= 5; плувамft= 2.3; charгл= 'ДА СЕ';

Автоматиченfn= [&документ за самоличност,&фута,&гл]()

{

документ за самоличност= 6;ft= 3.4;гл= 'В';

};

fn();

цена <<документ за самоличност<< ',' <<ft<< ',' <<гл<< 'н';

връщане 0;

}

Изходът е:

6, 3.4, Б

Потвърждаване, че имената на променливите във функционалното тяло на ламбда израза са за същите променливи извън ламбда израза.

Заснемане по стойност

При улавяне по стойност, копие от местоположението на променливата, от околния обхват, се предоставя в тялото на ламбда функцията. Въпреки че променливата в тялото на ламбда функцията е копие, нейната стойност не може да бъде променена в тялото в момента. За да се постигне улавяне по стойност, всяка променлива, повторена в клаузата за улавяне, не се предхожда от нищо. Следната програма илюстрира това:

#включва

използвайки пространство на именатачаса;

intглавен()

{

intдокумент за самоличност= 5; плувамft= 2.3; charгл= 'ДА СЕ';

Автоматиченfn= [id, ft, ch]()

{

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

цена <<документ за самоличност<< ',' <<ft<< ',' <<гл<< 'н';

};

fn();

документ за самоличност= 6;ft= 3.4;гл= 'В';

цена <<документ за самоличност<< ',' <<ft<< ',' <<гл<< 'н';

връщане 0;

}

Изходът е:

5, 2.3, А

6, 3.4, Б

Ако индикаторът за коментар бъде премахнат, програмата няма да се компилира. Компилаторът ще издаде съобщение за грешка, че променливите в дефиницията на тялото на функцията на ламбда израза не могат да бъдат променени. Въпреки че променливите не могат да се променят вътре в ламбда функцията, те могат да се променят извън ламбда функцията, както показва изходът на горната програма.

Смесване на улавяне

Заснемането чрез справка и улавянето по стойност може да се смесва, както показва следната програма:

#включва

използвайки пространство на именатачаса;

intглавен()

{

intдокумент за самоличност= 5; плувамft= 2.3; charгл= 'ДА СЕ'; boolбл= вярно;


Автоматиченfn= [id, фута,&ch,&бл]()

{

гл= 'В';бл= невярно;

цена <<документ за самоличност<< ',' <<ft<< ',' <<гл<< ',' <<бл<< 'н';

};

fn();


връщане 0;

}

Изходът е:

5, 2.3, В, 0

Когато всички заснети, са по справка:

Ако всички променливи, които трябва да бъдат уловени, са уловени чрез препратка, тогава само една & ще бъде достатъчна в клаузата за улавяне. Следната програма илюстрира това:

#включва

използвайки пространство на именатачаса;

intглавен()

{

intдокумент за самоличност= 5; плувамft= 2.3; charгл= 'ДА СЕ'; boolбл= вярно;


Автоматиченfn= [&]()

{

документ за самоличност= 6;ft= 3.4;гл= 'В';бл= невярно;

};

fn();

цена <<документ за самоличност<< ',' <<ft<< ',' <<гл<< ',' <<бл<< 'н';


връщане 0;

}

Изходът е:

6, 3.4, В, 0

Ако някои променливи трябва да бъдат уловени чрез препратка, а други по стойност, тогава една & ще представлява всички препратки, а останалите няма да бъдат предшествани от нищо, както показва следната програма:

използвайки пространство на именатачаса;

intглавен()

{

intдокумент за самоличност= 5; плувамft= 2.3; charгл= 'ДА СЕ'; boolбл= вярно;


Автоматиченfn= [&, id, ft]()

{

гл= 'В';бл= невярно;

цена <<документ за самоличност<< ',' <<ft<< ',' <<гл<< ',' <<бл<< 'н';

};

fn();


връщане 0;

}

Изходът е:

5, 2.3, В, 0

Обърнете внимание, че & самостоятелно (т.е. & не е последвано от идентификатор) трябва да бъде първият знак в клаузата за улавяне.

Когато всички заснети, са по стойност:

Ако всички променливи, които трябва да бъдат уловени, трябва да бъдат уловени по стойност, тогава само една = ще бъде достатъчна в клаузата за улавяне. Следната програма илюстрира това:

#включва

използвайки пространство на именатачаса;

intглавен()
{

intдокумент за самоличност= 5; плувамft= 2.3; charгл= 'ДА СЕ'; boolбл= вярно;


Автоматиченfn= [=]()

{

цена <<документ за самоличност<< ',' <<ft<< ',' <<гл<< ',' <<бл<< 'н';

};

fn();


връщане 0;


}

Изходът е:

5, 2.3, A, 1

Забележка : = е само за четене, към момента.

Ако някои променливи трябва да бъдат уловени по стойност, а други чрез препратка, тогава one = ще представлява всички копиеми променливи само за четене, а останалите ще имат &, както показва следната програма:

#включва

използвайки пространство на именатачаса;

intглавен()

{

intдокумент за самоличност= 5; плувамft= 2.3; charгл= 'ДА СЕ'; boolбл= вярно;


Автоматиченfn= [=,&ch,&бл]()

{

гл= 'В';бл= невярно;

цена <<документ за самоличност<< ',' <<ft<< ',' <<гл<< ',' <<бл<< 'н';

};

fn();


връщане 0;

}

Изходът е:

5, 2.3, В, 0

Обърнете внимание, че = самостоятелно трябва да бъде първият знак в клаузата за улавяне.

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

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

#включва

използвайки пространство на именатачаса;

char *изход;


Автоматиченcba= [](charнавън[])

{

изход=навън;

};



невалиденmainFunc(charвход[],невалиден (*за)(char[]))

{

(*за)(вход);

цена<<'за основна функция'<<'н';

}


невалиденfn()

{

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

}


intглавен()

{

charвход[] = 'за функция за обратно повикване';

mainFunc(вход, cba);

fn();

цена<<изход<<'н';



връщане 0;

}

Изходът е:

за основна функция

Сега

за функция за обратно повикване

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

Задният тип връщане

Типът на връщане на ламбда израз е автоматичен, което означава, че компилаторът определя типа на връщане от израза за връщане (ако има такъв). Ако програмистът наистина иска да посочи типа на връщане, той ще го направи както в следната програма:

#включва

използвайки пространство на именатачаса;

Автоматиченfn= [](intСпри се) -> int

{

intотговор=Спри се+ 3;

връщанеотговор;

};


intглавен()

{

Автоматиченвариаб=fn(2);

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


връщане 0;

}

Изходът е 5. След списъка с параметри се въвежда операторът със стрелка. Това е последвано от типа на връщане (int в този случай).

Закриване

Помислете за следния кодов сегмент:

структураКла

{

intдокумент за самоличност= 5;

charгл= 'да се';

}obj1, obj2;

Тук Cla е името на класа struct. Obj1 и obj2 са два обекта, които ще бъдат създадени от класа struct. Ламбда изразът е подобен в изпълнението. Определението на ламбда функцията е вид клас. Когато се извиква (извиква) ламбда функцията, обект се създава от дефиницията си. Този обект се нарича затваряне. Затварянето върши работата, която се очаква да свърши ламбдата.

Въпреки това, кодирането на ламбда израза, подобно на структурата по -горе, ще замени obj1 и obj2 с аргументите на съответните параметри. Следната програма илюстрира това:

#включва

използвайки пространство на именатачаса;

Автоматиченfn= [](intparam1,intparam2)

{

intотговор=param1+param2;

връщанеотговор;

} (2,3);


intглавен()

{

Автоматиченкъдето=fn;

цена <<където<< 'н';


връщане 0;

}

Резултатът е 5. Аргументите са 2 и 3 в скоби. Обърнете внимание, че извикването на функцията на ламбда израз, fn, не приема никакъв аргумент, тъй като аргументите вече са кодирани в края на дефиницията на ламбда функцията.

Заключение

Ламбда изразът е анонимна функция. Той се състои от две части: клас и обект. Определението му е един вид клас. Когато изразът е извикан, обект се формира от дефиницията. Този обект се нарича затваряне. Затварянето върши работата, която се очаква да свърши ламбдата.

За да може ламбда изразът да получи променлива от външен обхват на функцията, тя се нуждае от непразна клауза за улавяне в тялото на функцията.