Programmation fonctionnelle en C++ : niveau avancé

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Programmation fonctionnelle en C++ : niveau avancé



La programmation fonctionnelle (PF) est un paradigme dans lequel les calculs sont représentés comme l'évaluation de fonctions mathématiques, en évitant les changements d'état et les données mutables. Bien que C++ ait été initialement un langage orienté objet et procédural, à partir de la norme C++11, il a reçu des outils puissants pour la PF : les expressions lambda, std::function, std::bind, et en C++17 s'est ajouté le support de std::optional et std::variant, qui permettent d'implémenter des motifs monadiques. Dans cet article, nous examinerons les techniques avancées de programmation fonctionnelle en C++ : la composition de fonctions, le currying, le travail avec les monades et la création de fonctions pures à l'aide des fonctionnalités modernes du langage.



1. Expressions lambda et fonctions pures



Les expressions lambda sont la base du style fonctionnel en C++. Elles permettent de créer des fonctions anonymes sur place, ce qui est idéal pour les algorithmes de <algorithm>. Cependant, pour une véritable PF, il est important que les lambdas soient pures — c'est-à-dire qu'elles n'aient pas d'effets secondaires et ne dépendent pas d'un état mutable externe.



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

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

// Lambda pure : seulement des données d'entrée, seulement une sortie auto square = [](int x) { return x * x; };

// Application de transform sans effets secondaires 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;}


Pour une utilisation avancée, il convient d'éviter la capture par référence ([&]), sauf si cela est critique. La capture par valeur ([=]) ou l'énumération explicite des captures rend la lambda plus prévisible et testable.



2. Composition de fonctions avec std::function et opérateurs



La composition est l'union de deux ou plusieurs fonctions en une seule. En C++, on peut implémenter la composition à l'aide de templates et de std::function. Considérons un compositeur généralisé :



#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

// Composition de plusieurs fonctions auto triple = compose(multiplyByTwo, compose(addOne, addOne)); std::cout << triple(5) << std::endl; // ((5+1)+1)*2 = 14 return 0;}


Pour des chaînes plus complexes, on peut utiliser un opérateur de pipeline (similaire à |> dans d'autres langages). En C++20, il est possible de surcharger operator| pour créer une syntaxe pratique :



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


Cette approche rend le code déclaratif et facile à lire.



3. Currying et application partielle



Le currying — transformation d'une fonction de plusieurs arguments en

Blogs

Book Recommendations