Evgenii Legotckoi
Evgenii LegotckoiFeb. 13, 2018, 6:13 p.m.

Cooking lambda functions in C ++ - Part 1

My favorite tool in C ++ is lambda functions, although somehow they told me that they seem scary. In fact they are lovely. They greatly simplify the writing of programs and allow you to make quite interesting decisions.

But before considering various ways of using lambda functions, I suggest to familiarize yourself with the basic syntax of lambda functions.

Possible options for the syntax of lambda functions

[ capture ] ( params ) mutable exception attribute -> ret { body }
[ capture ] ( params ) -> ret { body }
[ capture ] ( params ) { body }
[ capture ] { body }

The first option is complete, but it is not forbidden to use abbreviated variations in the recording of functions.

  • capture - list of external capture objects, they can be captured both by reference and by copying.
  • params - list of parameters passed to the lambda function, this part will be similar to writing arguments for normal functions.
  • mutable - Using mutable allows you to modify copies of objects that have been captured by copying. In the normal version, they will not be modified.
  • exception - provides an exception specification, that is, lambda functions as well as normal functions can throw exceptions.
  • attribute - provides an attribute specification, there are only two such attributes defined in the C ++ specification ([[noreturn]], [[carries_dependency]])
  • params - list of parameters passed to the lambda function
  • ret - the return value of the lambda function

As for the return value, it can be automatically output from the object type, which is returned by the return statement. If the lambda function does not have a return statement, then the return value will be void.

The lambda function creates an unnamed temporary object of a unique unnamed non-union, non-aggregate type, known as a closure type. Thanks to the introduction of the auto operator in the modern C ++ standard, it is possible to declare the lambda object object fairly easily, without writing a std :: function declaration with all aprams and return values, which makes the code more simple and readable (for an experienced programmer, of course. that the newcomer will quickly suspect that something is wrong if the std :: function appears in the lambda declaration, but this is already a matter of practice).

Here is an example of declaring a simple lambda function that will return a void type, since at least one return statement is missing.

#include <iostream>

using namespace std;

int main()
{
    auto myLambda = []()
    {
        cout << "Hello World!" << endl;
    };

    myLambda();

    return 0;
}

Accordingly, the program code is not compiled if there are two or more return statements in the lambda function that will return objects of different types that are not connected by an inheritance hierarchy and which can not be reduced to a base class type. And even if these objects have a base class, it will be necessary to register the type of the return value, it will just be a pointer to the object of the base class (in the general case).

Here is an example of code that will not compile.

#include <iostream>

using namespace std;

class A
{
public:
    A(){}
};

class B : public A
{
public:
    B(){}
};

class C : public A
{
public:
    C(){}
};

int main()
{
    auto myLambda = [](int type)
    {
        if (type == 0)
        {
            return new B();
        }
        else
        {
            return new C();
        }
    };

    myLambda(0);

    return 0;
}

You must specify the return type

auto myLambda = [](int type) -> A* // Let's specify the type of the return value
{
    if (type == 0)
    {
        return new B();
    }
    else
    {
        return new C();
    }
};

Also, the compilation error will occur if you do not specify the return type and you create an object inside the lambda function in the heap, but in some cases you can return the pointer to nullptr . That is, the following code is not compiled.

#include <iostream>

using namespace std;

class A
{
public:
    A(){}
};


int main()
{
auto myLambda = [](int type)
{
    if (type == 0)
    {
        return new A();
    }
    else
    {
        return nullptr;
    }
};

    myLambda(0);

    return 0;
}

Again you need to specify the type of the return value

auto myLambda = [](int type) -> A* // Let's specify the type of the return value
{
    if (type == 0)
    {
        return new A();
    }
    else
    {
        return nullptr;
    }
};

The fact is that nullptr is a universal data type, which in some sense is not a data type, because it can not be set as a variable type. But it can be assigned as a value to a pointer to an object. In order for the implicit conversion to occur correctly in this case, you must also specify the type of the return value.

Also in the above example, we show how to call a lambda function and pass parameters to it. Noticed? In this example, the int type parameter is used, depending on which we return a pointer to the created object or nullptr .

Also in lambda functions there is the concept of capturing variables. This means that the lambda function can use not only variables that are passed to it as parameters, but also any objects that have been declared outside the lambda function.

The symbol list can be transferred as follows:

  • **[a,&b]**
    where a is captured by value, and b is captured by reference.
  • **[this]**
    grabs the this pointer by value.
  • **[&]**
    capture all characters by reference
  • **[=]**
    capture all characters by value
  • **[]**
    nothing captures

About the capture of variables, let's talk in the next articles.

But I note one interesting point, the lamda function can be called immediately where you declared it, if you add parentheses after the body of the lame function and pass all the necessary parameters, if any.

For example, this code is also compiled

#include <iostream>

using namespace std;

class A
{
public:
    A(){}
};


int main()
{

    A* myA = [](int type) -> A*
    {
        if (type == 0)
        {
            return new A();
        }
        else
        {
            return nullptr;
        }
    }(0);

    return 0;
}

So think about whether the following code is compiled?

int main(){[](){}();}
We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

Comments

Only authorized users can post comments.
Please, Log in or Sign up
e
  • ehot
  • March 31, 2024, 9:29 p.m.

C++ - Тест 003. Условия и циклы

  • Result:78points,
  • Rating points2
B

C++ - Test 002. Constants

  • Result:16points,
  • Rating points-10
B

C++ - Test 001. The first program and data types

  • Result:46points,
  • Rating points-6
Last comments
k
kmssrFeb. 9, 2024, 2:43 a.m.
Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lesson 007. Working with ICMP Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVADec. 25, 2023, 6:30 p.m.
Boost - static linking in CMake project under Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJoDec. 25, 2023, 4:38 p.m.
Boost - static linking in CMake project under Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
GvozdikDec. 19, 2023, 5:01 a.m.
Qt/C++ - Lesson 056. Connecting the Boost library in Qt for MinGW and MSVC compilers Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Now discuss on the forum
a
a_vlasovApril 14, 2024, 1:41 p.m.
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
Павел Дорофеев
Павел ДорофеевApril 14, 2024, 9:35 a.m.
QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
f
fastrexApril 4, 2024, 11:47 a.m.
Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…
AC
Alexandru CodreanuJan. 19, 2024, 7:57 p.m.
QML Обнулить значения SpinBox Доброго времени суток, не могу разобраться с обнулением значение SpinBox находящего в делегате. import QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: tr…

Follow us in social networks