Анонимные функции. Лямбда функции
В языке C++ есть возможность создавать анонимные функции или же лямбда функции, т.е. функции без имени.
Зачем это надо? Иногда для какого-либо теста или однократного выполнения какой-то операции не требуется создавать «глобальную» функцию, которая может использоваться многократно в документе.
Также одним из преимуществ лямбда-функций является «управление зоной видимости» мы можем сами выбрать какие переменные и каким образом нам видны!
Рассмотрим стандартную функцию:
int a=5;
void Func()
{
cout << "Hello World! " <<a<< endl;
}
int main()
{
Func();
return 0;
}
Как наглядно видно, функция Func() объявлена ЗА ПРЕДЕЛАМИ функции main, и ей видны все глобальные переменные данного документа, например int a=5;.
Теперь рассмотрим лямбда-функцию:
ее синтаксис выглядит так:
[/*видимые переменные*/](/*аргументы*/)
{
//тело функции
};
Например:
auto pf=[]()
{
cout << "Hello World! "<< endl;
};
pf1();
auto pf2=[](int b)
{
cout << "Hello World! b="<<b<< endl;
};
pf2(10);
В обоих случаях мы использовали буфер-указатель pf.., но можно обойтись и без него.
Теперь самый главный момент с видимостью переменных – хоть мы и вызываем функцию внутри main, но по факту ее зона видимости (контекст) вне этой функции, т.е. она близка к функции Func()из первого примера, она может видеть глобальные переменные, но локальные внутри функции main она САМА ПО СЕБЕ не видит, что бы «указать» ей локальные переменные можно применить следующие способы:
int a=5;
int main()
{
int c=10;
auto pf2=[&c]()
{
cout << "Hello World! a=" <<a<<" c= "<<c<< endl;
};
pf2();
return 0;
}
Мы можем передать переменные в зону видимости лямбда-функции:
- через ссылку, как в примере выше auto pf2=[&c]()
В этом случае мы можем изменять переменные - по значению auto pf2=[c]()
В этом случае мы НЕ МОЖЕМ ИЗМЕНЯТЬ ЛОКАЛЬНЫЕ переменные - по значению с ключевым словом mutable auto pf2=[c]()mutable
В этом случае мы МОЖЕМ ИЗМЕНЯТЬ ЛОКАЛЬНЫЕ переменные!!! НЕ «оригинальные» - можем часть передать по ссылке, а часть по значению, указывая их через запятую
- можем все переменные, написанные выше принять по ссылке auto pf2=[&]()
- можем все переменные, написанные выше принять по значению auto pf2=[=]()
- внутри класса вы можем указать этот класс используя ключевое слово this auto pf2=[this]()
Важное примечание: хоть функция является анонимной и якобы написана внутри функции main ее контекст (зона видимости) расположена выше, в «глобальной зоне видимости» поэтому код
int main()
{
int c=10;
[=]()
{
cout << "Hello World! a=" <<a<<" c= "<<c<< endl;
};
cout << "End code"<< endl;
return 0;
}
Выведет только «End code» т.к. вызова функции НЕ БЫЛО мы только написали ее реализацию, но не вызвали ее.
Как было сказано ранее не обязательно использовать буфер в виде полиморфной обертки, в ряде случаев (например при передаче в качестве аргумента в другую функцию) можнео сразу писать лямбда-функцию.
Например:
int a=5;
void Func_in_func(function<void()> Function)
{
cout<< "Call func in func"<<endl;
Function();
}
int main()
{
int c=10;
Func_in_func([=]()
{
cout << "Hello World! a=" <<a<<" c= "<<c<< endl;
});
return 0;
}