1 2 3 4 |
//Листинг #1 Лямбда-функция C++11 mingw int main(){ []{}; } |
1 2 3 4 5 6 7 8 9 |
//Листинг #2 Использование лямбда-функции C++11 mingw #include <iostream> using namespace std; int main() { []{ cout << "lambda-func\n"; }; //Это объявление []{ cout << "lambda-func\n"; }(); //А вызов делается с помощью круглых скобок в конце } |
1 2 3 4 5 6 7 8 9 10 |
//Листинг #3 Лямбда-функции Параметры и аргументы С++11 mingw #include <iostream> using namespace std; int main() { [](const int x){ cout << "x == " << x; }(10); //Отдаём аргументы cout << "\n\n"; [](const int x, const double d){ cout << "x == " << x << "\nd == " << d; }(10, 20.3); //Принимаем в параметры лямбда-функции переданные значения } |
1 2 3 4 5 6 7 8 9 |
//Листинг #4.1 Лямбда-функции Захват по значению #include <iostream> int main() { int x; [x]{ x++; }; //захвачен x, но попытка изменить значение x //приводит к ошибке компиляции } |
1 2 3 4 5 6 7 8 9 10 11 |
//Листинг #4.2 Лямбда-функции Захват по значению #include <iostream> using std::cout; int main() { int x = 10; [x]{ cout << x; }(); //захвачен x, выводим значение на экран } |
1 2 3 4 5 6 7 8 9 10 11 12 |
//Листинг #5 Лямбда-функции Захват по ссылке #include <iostream> using std::cout; int main() { int x = 10; [&x](){ x++; }(); //Изменяем x внутри, не забываем запустить лямбда-функцию cout << x << '\n'; //x поменял своё значение } |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
//Листинг #6.1 Лямбда-функции Захваты #include <iostream> using std::cout; int main() { int x = 10; double y = 5.5; [&x, y](){ }(); //захват x по ссылке, y по значению } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
//Листинг #6.2 Захват всех значений из доступной области видимости #include <iostream> using std::cout; int main() { int x = 10; double y = 5.5; [&](){ x++, y = y + 10; }(); //захват всех значений по ссылке из текущей области видимости cout << "x == " << x << '\n'; //11 cout << "y == " << y << '\n'; //15 } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//Листинг #6.3 Лямбда-функции Захваты #include <iostream> using std::cout; int main() { int x = 10; double y = 5.5; [=](){ int z = x; }(); //захват всех значений по значению из текущей области видимости } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//Листинг #6.4 Лямбда-функции Захваты #include <iostream> using std::cout; class MyClass{ const int x = 100; public: void show(){ [this]{ cout << x; }(); //захват this } }; int main() { MyClass m; m.show(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
//Листинг #6.5 Лямбда-функции Захваты #include <iostream> using std::cout; class MyClass{ int x = 100; double y = 5.5; public: void foo(){ int y = z; [this] {x++; y = 20; ////z++;}(); //захват this, все переменные класса стали доступны //но не внешние переменные области видимости лямбда-функции!! } void print() const { cout << "x == " << x << '\n'; cout << "y == " << y << '\n'; } }; int main() { MyClass m; m.foo(); m.print(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//Листинг #7 Лямбда-функции Захватывать можно только переменные с автоматическим классом хранения mingw C++11 #include <iostream> using std::cout; int global_value = 10; int main() { [=](){ x++; }(); cout << global_value << '\n'; //всё удачно скомпилировалось } |
******************
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
//Листинг #8 Запоминание лямбда-функций в объекты C++11 mingw #include <iostream> #include <functional> using std::cout; int main() { auto lambda_fun1 = []{}; //Запомнили лямбда-функцию в объект auto lambda_fun2 = []{ return 200; }; //Запомнили лямбда-функцию в объект auto hello_world1 = []{ cout << "hello"; }; auto hello_world2 = [](const char* S){ cout << S; }; //вызываем лямбда-функции с помощью объектов-хранителей lambda_fun1(); //пустая, ничего не произойдёт lambda_fun2(); //ничего не произойдёт cout << lambda_fun2() << '\n'; //выведет на экран 200 cout << '\n'; hello_world1(); //выведет на экран "hello" cout << '\n'; hello_world2("hi-hi-hi"); //выведет на экран "hi-hi-hi" } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
////Листинг #9.1 Возникновение необходимости явного указания возвращаемого из лямбда-функции типа C++11 mingw #include <iostream> using std::cout; int main() { auto lambda_fun = []{ int x = 10; if (x == 10) return 5; else return 1.6; //компилятор не знает, что выбрать для результирующего объекта лямбды: int или double }; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
////Листинг #9.2 Возникновение необходимости явного указания возвращаемого из лямбда-функции типа C++11 mingw #include <iostream> using std::cout; int main() { auto lambda_fun = []()->double{ //явно указываем, что возвращаемый тип будет double int x = 10; if (x == 10) return 5; else return 1.6; //теперь всё ОК }; cout << lambda_fun(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
//Листинг #10.1 Передаём лямбда-функцию в независимую функцию C++11 mingw #include <iostream> using std::cout; void foo(double (*ptr)()){ //Создали функцию для приёма лямбда-функции cout << ptr() << '\n'; //приняли лямбда-функцию в ptr и используем её } int main() { auto lambda_fun = []()->double{ //явно указываем, что возвращаемый тип будет double int x = 10; if (x == 10) return 5; else return 1.6; //теперь всё ОК }; foo(lambda_fun); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
//Листинг #10.2 Передаём лямбда-функцию в независимую функцию C++11 mingw #include <iostream> #include <functional> using std::cout; using std::function; void foo(function<double()> ptr){ //Создали функцию для приёма лямбда-функции cout << ptr() << '\n'; //приняли лямбда-функцию в ptr и используем её } int main() { auto lambda_fun = []()->double{ return 200.5; }; foo(lambda_fun); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
//Листинг #10.3 Передаём лямбда-функцию в независимую функцию C++11 mingw //использование std::functional #include <iostream> #include <functional> #include <string> using std::cout; using std::function; using std::string; void foo(function<double(int, string)> ptr){ //2. Типы этих параметров указываются в круглых скобках cout << ptr(0, "") << '\n'; //3. Вызываем нашу лямбда-функцию,не забываем, что она сейчас с параметрами } int main() { auto lambda_fun = [](int x, string S)->double{ //1. у лямбда-функции появились параметры return 200.5; }; foo(lambda_fun); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
//Листинг #10.4 Передаём лямбда-функцию в независимую функцию C++11 mingw //использование шаблонов #include <iostream> #include <functional> #include <string> using std::cout; using std::function; using std::string; template <typename T> void foo(T ptr){ //Тип автоматически подставится cout << ptr(0, "") << '\n'; } int main() { auto lambda_fun = [](int x, string S)->double{ //1. у лямбда-функции появились параметры return 200.5; }; foo(lambda_fun); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
//Листинг #12 #include <iostream> using std::cout; int main() { int x = 1; int y = 2; auto lambda_fun = [x, &y]{ cout << "x == " << x << '\n'; cout << "y == " << y << '\n'; cout << "\n\n"; }; lambda_fun(); //1,2 x = y = 100; lambda_fun(); //1,100 x = 200; lambda_fun(); //1,100 y = 77; lambda_fun(); //1,77 } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <iostream> #include <functional> using std::cout; int main() { int x = 10; auto lambda_func = [x]() mutable{ return ++x; }; cout << lambda_func() << '\n'; cout << lambda_func() << '\n'; cout << lambda_func() << '\n'; } |
1 2 3 4 5 6 7 8 9 |
//Листинг #13.1 Пересылка лямбда-функции в другую функцию void foo(void (*p)()){ p(); //выполняем пришедшую функцию } int main() { auto lambda = []{}; //аналог функции void lambda(){} foo(lambda); //пересылаем лямбда-функцию в foo и там и запускаем } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//Листинг #13.2 Пересылка лямбда-функции в другую функцию #include <iostream> #include <string> using std::string; using std::cout; void foo(void (*p)(string)){ p("HELLO"); //выполняем пришедшую функцию } int main() { auto lambda = [](string S){ cout << S << '\n'; }; //аналог функции void lambda(string){} foo(lambda); //пересылаем лямбда-функцию в foo и там и запускаем } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
//Листинг #13.3 Пересылка лямбда-функции в лямбда-функцию #include <iostream> #include <string> using std::string; using std::cout; int main() { auto lambda = [](string S){ cout << S << '\n'; }; //ВАРИАНТ1 [](auto type){ type("HELLO"); }(lambda); //вызов на месте cout << '\n'; //ВАРИАНТ2 auto my_func = [](auto type){ type("my_func"); }; //Запомнили в объект my_func(lambda); //использовали запомненный объект } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
//Листинг #14.1 Неудачная попытка передачи лямбда-функции в параметр другой функции #include <iostream> #include <string> using std::string; using std::cout; void foo(void (*ptr)()){ ptr(); } int main() { int x; auto lambda = [&](){ x++; }; foo(lambda); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//Листинг #14.2 Попытка привести лямбда-функцию к указателю на функцию #include <string> using std::string; using std::cout; void foo(void (*ptr)()){ ptr(); } int main() { int x; auto lambda = [&](){}; foo(lambda); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
//Листинг #15.1 Использование std::function #include <iostream> #include <functional> using std::function; //используем тип для приёма функций using std::cout; void foo(function<void()> ptr){ ptr(); } int main() { int x = 100; auto lambda = [&](){ x++; }; foo(lambda); cout << x << '\n'; //теперь x == 101 } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
//Листинг #15.2 Использование std::function #include <iostream> #include <functional> using std::function; //используем тип для приёма функций using std::cout; void foo(function<double()> ptr){ //std::function для функции типа double foo() ptr(); } int main() { int x = 100; auto lambda = [&]()->double{ return x++; }; //тип возвращаемого объекта double foo(lambda); cout << x << '\n'; //теперь x == 101 } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
//Листинг #15.3 Использование std::function #include <iostream> #include <functional> #include <string> using std::function; //используем тип для приёма функций using std::cout; using std::string; void foo(function<double(string)> ptr){ //std::function для функции типа double foo(string) ptr("HELLO"); } int main() { int x = 100; auto lambda = [&](string)->double{ return x++; }; //лямбда-функция соответствует функции double lambda(string) foo(lambda); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//Листинг #16 Немного запутались, будьте внимательны к вызовам функций и к использованию их названий не для вызова #include <iostream> using std::cout; int main() { auto lambda = [] () { return 0; }(); //поскольку функция вызывается, то в lambda сохранится 0, а не лямбда-функция cout << lambda << '\n'; //можно не заметить подвох cout << lambda() << '\n'; //вызов функции должен был происходить так, но сейчас оно не функция } |
Замыкание (closure) — результирующий объект, создаваемый лямбда-функцией.
Класс замыкания (closure class) — класс, из которого инстанцируется замыкание.
Лямбда-интродьюсер — Те скобки, которые предназначены для захвата, со всем своим содержимым.
trailing-return-type — возвращаемый из лямбды явно тип для создаваемого лямбдой конечного объекта
capture-list — список захватываемых объектов. В него входят все те значения, которые захватываются явно. Общее обозначение всего того, что не &, =, this,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
//Листинг #17 Захват this C++17 #include <iostream> class MyClass { int x; public: int y; void my_method(){ [=]{ //Вы можете думать, что захватили лямбдой {х}, но это не так //{x} не локальная переменная, а атрибут класса //вы захватили {this} вместо {x} }; // [x]{} //Поскольку {x} атрибут класса, вы не можете захватить его как обычную переменную // [this->x]{}; //И даже так не выйдет, потому что область видимости атрибутов //это то же, что если бы вы обращались к {х}, //а он в другой зоне видимости //Можно захватить сам {this}, тогда все атрибуты класса станут доступны лямбде [this]{ x; y; }; //Теперь и {x} и {y} доступны лямбде //А можно захватывать отдельные атрибуты [x=x]{}; //создание внутренней для лямбда одноимённой копии {x} [&x=x]{}; //создание внутренней для лямбда одноимённо ссылки на атрибут {x} //Можно сделать вне лямбда-функции ссылку на атрибут int &rx = x; [rx]{}; //захватили {x} по значению, внутри лямбды {rx} то же, что настоящий {x} [&rx]{}; //захватили ссылку на {x} } }; int main() { } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
//Листинг #18.1 Захваты #include <iostream> using std::cout; int main() { int x,y,z; [&]{}; //захват всех локальных переменных из области видимости лямбда //по ссылке [=]{}; //захват всех по значению [=,&y]{}; //захват всех по значению, за исключением {y}, //который хватается по ссылке [&z, y]{}; //захват {z} по ссылке, {y} по значению [x = x]{}; //С++14, создание локальной в лямбда х и присваивание хватаемого х [&x =x]{}; //C++14, создание внутри лямбда ссылки и адресация её на внешний локальный x // [this]{}; //захват указателя {this} //для классов // [*this]{}; //захват казателя {this} по значению //для классов [x](int x) mutable throw() ->int { cout << "OK"; } (100); //пример полной формы } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
//Листинг #18.2 Захваты #include <iostream> using std::cout; class MyClass{ int x,y,z; public: MyClass():x(100),y(200),z(300){}; //инициализация атрибутов класса значениями void m1(); void m2(); void m3(); }; void MyClass::m1(){ [this]{ //захват указателя this x = 150; //выполняется как если бы мы захватывали скопом атрибуты по ссылке y = 250; x = 150; }(); //выполняем лямбда-функцию cout << "x == " << x << '\n'; //настоящие атрибуты поменяли свои значения cout << "y == " << y << '\n'; cout << "z == " << z << '\n'; } void MyClass::m2(){ [*this]{ //захват указателя this по значению x = 150; //атрибуты получили абилку {только для чтения}, y = 250; //как если бы мы их захватывали по значению, x = 150; //поэтому не компилируется }(); cout << "x == " << x << '\n'; cout << "y == " << y << '\n'; cout << "z == " << z << '\n'; } int main() { MyClass mc; mc.m1(); } |
1 2 3 4 5 6 |
int main(){ int x(100), y(200), z(300); //локальные переменные [=]{}; //ничего не захвачено [=]{ x++; z++;}; //захвачены x и z } |
1 2 3 4 5 6 |
int main(){ int x(100), y(200), z(300); //локальные переменные [x]{}; //захвачены x, хоть и не использован } |
Спасибо автору! Написанное очень помогло!
Увидеть бы пример создания массива указателей на Лямбда функции. Статья классная.
Само собой, массив указателей на функции предполагает, как и любой массив, что в хранении будут использоваться однотипные данные или ссылки на однотипные данные, т. е. сейчас лямбда-функции в массиве все должны быть с одинаковой сигнатурой. А так это обычный масив указателей на функции.
Для лямбд с захватом надо использовать std::function, использовать обычные указатели на лямбды с захватом не получится.
проверил работает? В квадратных скобочках можно передавать параметры для захвата контекста как угодно а в аргументах лямбды как и сказал админ всё должно совпадать. А здесь не приходят уведомления на эл. почту если вам отвечают?
Мне? Приходят. Незарегистрированным, наверное, нет, не знаю. Регистрацию я вроде убрал. Есть некоторые технические сложности и моё незнание, мешающие исправить это. Впрочем, вернул регистрацию. Но вход может плохо работать: в смысле, что при правильных входных авторизации пишет будто неверный логин или пароль (в теме сайта устаревший код, из-за чего такая фигня).
Сообщение написано непонятно: Вы что, себя спрашиваете и себе отвечаете?