44. C++ Анонимные функции. Лямбда функции

Анонимные функции. Лямбда функции

В языке 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;
}

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *