C ++

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

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

Защо 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<връщане 0;

Резултатът е:

за основна функция
Сега
за функция за обратно извикване

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

Типът завършващо връщане

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

#include
използване на пространство от имена std;
auto fn = [] (int param) -> int

int отговор = param + 3;
връщане отговор;
;
int main ()

автоматична променлива = fn (2);
Cout << variab << '\n';
връщане 0;

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

Закриване

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

Структура Кла

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

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

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

#include
използване на пространство от имена std;
автоматично fn = [] (int param1, int param2)

int отговор = param1 + param2;
връщане отговор;
(2, 3);
int main ()

автоматично var = fn;
Cout << var << '\n';
връщане 0;

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

Заключение

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

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

Урок Сянка на Tomb Raider за Linux
Shadow of the Tomb Raider е дванадесетото допълнение към поредицата Tomb Raider - франчайз за екшън-приключенска игра, създаден от Eidos Montreal. Игр...
Как да увеличите FPS в Linux?
FPS означава Кадри в секунда. Задачата на FPS е да измерва честотата на кадрите при възпроизвеждане на видео или игрални изпълнения. С прости думи бро...
Топ Oculus App Lab Games
Ако сте собственик на слушалки на Oculus, тогава трябва да знаете за странично зареждане. Sideloading е процесът на инсталиране на несъхранявано съдър...