Evgenii Legotckoi
Evgenii Legotckoi13. Februar 2018 18:13

Lambda-Funktionen in C++ kochen - Teil 1

Mein Lieblingswerkzeug in C++ sind Lambda-Funktionen, obwohl mir gesagt wurde, dass sie beängstigend aussehen. Tatsächlich sind sie bezaubernd. Sie vereinfachen das Schreiben von Programmen erheblich und ermöglichen es Ihnen, einige ziemlich interessante Entscheidungen zu treffen.

Aber bevor Sie sich die verschiedenen Verwendungen von Lambda-Funktionen ansehen, schlage ich vor, dass Sie sich mit der grundlegenden Syntax von Lambda-Funktionen vertraut machen.

Mögliche Syntaxoptionen für Lambda-Funktionen

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

Die erste Option ist vollständig, aber es ist nicht verboten, abgekürzte Varianten der Schreibweise von Funktionen zu verwenden.

  • capture - Liste externer erfasster Objekte, sie können sowohl durch Referenz als auch durch Kopieren erfasst werden.
  • params - Liste von Parametern, die an Lambda-Funktionen übergeben werden. Dieser Teil ähnelt dem Schreiben von Argumenten für reguläre Funktionen.
  • mutable - Mit mutable können Sie Kopien von Objekten ändern, die von der Kopie erfasst wurden. Normalerweise werden sie nicht geändert.
  • Ausnahme – stellt eine Ausnahmespezifikation bereit, d. h. Lambda-Funktionen können genau wie normale Funktionen Ausnahmen auslösen.
  • attribute - stellt eine Attributspezifikation bereit, es gibt nur zwei solcher Attribute in der C++-Spezifikation ([[noreturn]], [[carries_dependency]])
  • params - Liste der an die Lambda-Funktion übergebenen Parameter
  • ret - Rückgabewert der Lambda-Funktion

Der Rückgabewert kann automatisch aus dem Objekttyp abgeleitet werden, der von der return-Anweisung zurückgegeben wird. Wenn die Lambda-Funktion keine return-Anweisung enthält, ist der Rückgabewert ungültig.

Eine Lambda-Funktion erstellt ein unbenanntes temporäres Objekt eines eindeutigen, unbenannten, nicht gewerkschaftlichen, nicht aggregierten Typs, bekannt als closure type. Dank der Einführung des auto -Operators im modernen C++-Standard ist es möglich, a zu deklarieren Lambda-Funktionsobjekt ziemlich einfach, ohne eine Funktordeklaration ( * std::function * ) mit allen Parametern und Rückgabewerten zu schreiben, was den Code einfacher und lesbarer macht (natürlich für einen erfahrenen Programmierer. Natürlich Sie berücksichtigen, dass ein Anfänger schnell vermuten wird, dass etwas nicht stimmt, wenn std::function in der Lambda-Deklaration auftaucht, aber das ist Übungssache).

Hier ist ein Beispiel für die Deklaration einer einfachen Lambda-Funktion, die einen void -Typ zurückgibt, weil mindestens eine return -Anweisung fehlt.

#include <iostream>

using namespace std;

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

    myLambda();

    return 0;
}

Dementsprechend wird der Programmcode nicht kompiliert, wenn es zwei oder mehr Rückgabeanweisungen in der Lambda-Funktion gibt, die Objekte unterschiedlicher Typen zurückgeben, die nicht durch eine Vererbungshierarchie verbunden sind und nicht in den Basisklassentyp umgewandelt werden können. Und selbst wenn diese Objekte eine Basisklasse haben, muss der Typ des Rückgabewerts angegeben werden, es ist nur ein Zeiger auf das Basisklassenobjekt (im allgemeinen Fall).

Hier ist ein Beispiel für Code, der nicht kompiliert werden kann.

#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;
}

Sie müssen den Rückgabetyp angeben

auto myLambda = [](int type) -> A* // Укажем тип возвращаемого значения
{
    if (type == 0)
    {
        return new B();
    }
    else
    {
        return new C();
    }
};

Außerdem tritt ein Kompilierungsfehler auf, wenn Sie den Typ des Rückgabewerts nicht angeben und gleichzeitig ein Objekt auf dem Heap innerhalb der Lambda-Funktion erstellen, aber in einigen Fällen können Sie einen Zeiger auf * nullptr. zurückgeben. * Das heißt, der folgende Code wird nicht kompiliert.

#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;
}

Auch hier müssen Sie den Typ des Rückgabewerts angeben.

auto myLambda = [](int type) -> A* // Укажем тип возвращаемого значения
{
    if (type == 0)
    {
        return new A();
    }
    else
    {
        return nullptr;
    }
};

Der Punkt ist, dass nullptr ein generischer Datentyp ist, der in gewissem Sinne kein Datentyp ist, da er nicht als Variablentyp festgelegt werden kann. Aber es kann einem Zeiger auf ein Objekt als Wert zugewiesen werden. Damit die implizite Konvertierung in diesem Fall korrekt funktioniert, müssen Sie auch den Typ des Rückgabewerts angeben.

Das obige Beispiel zeigt auch, wie man eine Lambda-Funktion aufruft und ihr Parameter übergibt. Bemerkte? In diesem Beispiel wird der Parameter int type verwendet, je nachdem, ob wir einen Zeiger auf das erstellte Objekt oder nullptr zurückgeben.

Auch in Lambda-Funktionen gibt es das Konzept der Erfassung von Variablen. Das bedeutet, dass die Lambda-Funktion nicht nur die ihr übergebenen Variablen als Parameter verwenden kann, sondern auch alle Objekte, die außerhalb der Lambda-Funktion deklariert wurden.

Eine Liste von Zeichen kann wie folgt übergeben werden:

  • **[a,&amp;b]**
    wobei a als Wert erfasst wird und b als Referenz erfasst wird.
  • **[this]**
    schnappt sich den
    **this**
    -Zeiger nach Wert.
  • **[&amp;]**
    erfasst alle Zeichen per Referenz
  • **[=]**
    erfasst alle Zeichen nach Wert
  • **[]**
    erfasst nichts

Wir werden in den folgenden Artikeln über das Erfassen von Variablen sprechen.

Aber ich werde einen interessanten Punkt anmerken, die Lambda-Funktion kann sofort dort aufgerufen werden, wo Sie sie deklariert haben, wenn Sie Klammern nach dem Hauptteil der Lambda-Funktion hinzufügen und alle erforderlichen Parameter übergeben, falls vorhanden.

Dieser Code wird beispielsweise auch kompiliert

#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;
}

Denken Sie also darüber nach, wird der folgende Code kompiliert?

int main(){[](){}();}
Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Stabiles Hosting des sozialen Netzwerks EVILEG. Wir empfehlen VDS-Hosting für Django-Projekte.

Magst du es? In sozialen Netzwerken teilen!

Kommentare

Nur autorisierte Benutzer können Kommentare posten.
Bitte Anmelden oder Registrieren
Letzte Kommentare
ИМ
Игорь Максимов5. Oktober 2024 07:51
Django – Lektion 064. So schreiben Sie eine Python-Markdown-Erweiterung Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas55. Juli 2024 11:02
QML - Lektion 016. SQLite-Datenbank und das Arbeiten damit in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssr8. Februar 2024 18:43
Qt Linux - Lektion 001. Autorun Qt-Anwendung unter Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lektion 007. Arbeiten mit ICMP-Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25. Dezember 2023 10:30
Boost - statisches Verknüpfen im CMake-Projekt unter Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
Jetzt im Forum diskutieren
J
JacobFib17. Oktober 2024 03:27
добавить qlineseries в функции Пользователь может получить любые разъяснения по интересующим вопросам, касающимся обработки его персональных данных, обратившись к Оператору с помощью электронной почты https://topdecorpro.ru…
JW
Jhon Wick1. Oktober 2024 15:52
Indian Food Restaurant In Columbus OH| Layla’s Kitchen Indian Restaurant If you're looking for a truly authentic https://www.laylaskitchenrestaurantohio.com/ , Layla’s Kitchen Indian Restaurant is your go-to destination. Located at 6152 Cleveland Ave, Colu…
КГ
Кирилл Гусарев27. September 2024 09:09
Не запускается программа на Qt: точка входа в процедуру не найдена в библиотеке DLL Написал программу на C++ Qt в Qt Creator, сбилдил Release с помощью MinGW 64-bit, бинарнику напихал dll-ки с помощью windeployqt.exe. При попытке запуска моей сбилженной программы выдаёт три оши…
F
Fynjy22. Juli 2024 04:15
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

Folgen Sie uns in sozialen Netzwerken