Funktionale Programmierung in C++: Fortgeschrittenes Niveau

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Funktionale Programmierung in C++: Fortgeschrittenes Niveau



Funktionale Programmierung (FP) ist ein Paradigma, bei dem Berechnungen als Auswertung mathematischer Funktionen dargestellt werden, wobei Zustandsänderungen und veränderliche Daten vermieden werden. Obwohl C++ ursprünglich eine objektorientierte und prozedurale Sprache war, erhielt es ab dem Standard C++11 leistungsstarke Werkzeuge für FP: Lambda-Ausdrücke, std::function, std::bind, und in C++17 kam die Unterstützung für std::optional und std::variant hinzu, die die Implementierung monadischer Muster ermöglichen. In diesem Artikel betrachten wir fortgeschrittene Techniken der funktionalen Programmierung in C++: Funktionskomposition, Currying, Arbeit mit Monaden und die Erstellung reiner Funktionen mit modernen Sprachfeatures.



1. Lambda-Ausdrücke und reine Funktionen



Lambda-Ausdrücke sind die Grundlage des funktionalen Stils in C++. Sie ermöglichen die Erstellung anonymer Funktionen direkt an Ort und Stelle, was ideal für Algorithmen aus <algorithm> ist. Für echte FP ist es jedoch wichtig, dass Lambdas rein sind – das heißt, sie haben keine Seiteneffekte und hängen nicht von externem veränderlichem Zustand ab.



#include <iostream>#include <vector>#include <algorithm>

int main() { std::vector<int> numbers = {1, 2, 3, 4, 5};

// Reines Lambda: nur Eingabedaten, nur Ausgabe auto square = [](int x) { return x * x; };

// Wende transform ohne Seiteneffekte an std::vector<int> squared; std::transform(numbers.begin(), numbers.end(), std::back_inserter(squared), square);

for (int n : squared) std::cout << n << " "; // 1 4 9 16 25 return 0;}


Für fortgeschrittene Verwendung sollte das Erfassen per Referenz ([&]) vermieden werden, wenn es nicht kritisch ist. Erfassen per Wert ([=]) oder explizite Auflistung der Erfassungen macht das Lambda vorhersagbarer und testbarer.



2. Funktionskomposition mit std::function und Operatoren



Komposition ist die Kombination von zwei oder mehr Funktionen zu einer. In C++ kann Komposition mit Templates und std::function implementiert werden. Betrachten wir einen verallgemeinerten Kompositor:



#include <functional>#include <iostream>

template <typename F, typename G>auto compose(F f, G g) { return [f, g](auto x) { return f(g(x)); };}

int main() { auto addOne = [](int x) { return x + 1; }; auto multiplyByTwo = [](int x) { return x * 2; };

auto addThenMultiply = compose(multiplyByTwo, addOne); std::cout << addThenMultiply(5) << std::endl; // (5+1)*2 = 12

// Komposition mehrerer Funktionen auto triple = compose(multiplyByTwo, compose(addOne, addOne)); std::cout << triple(5) << std::endl; // ((5+1)+1)*2 = 14 return 0;}


Für komplexere Ketten kann ein Pipeline-Operator (ähnlich |> in anderen Sprachen) verwendet werden. In C++20 besteht die Möglichkeit, operator| zu überladen, um eine bequeme Syntax zu schaffen:



#include <functional>#include <iostream>

template <typename F>class Pipeable { F f;public: Pipeable(F func) : f(func) {} template <typename T> auto operator()(T x) const { return f(x); }};

template <typename T, typename F>auto operator|(T x, Pipeable<F> p) { return p(x);}

int main() { auto addOne = Pipeable([](int x) { return x + 1; }); auto square = Pipeable([](int x) { return x * x; });

int result = 5 | addOne | square; // (5+1)^2 = 36 std::cout << result << std::endl; return 0;}


Dieser Ansatz macht den Code deklarativ und leicht lesbar.



3. Currying und partielle Anwendung



Currying – Umwandlung einer Funktion mit mehreren Argumenten in

Blogs

Buchempfehlungen