Programmation fonctionnelle en C++ : fonctionnalités modernes et exemples
La programmation fonctionnelle (PF) est un paradigme dans lequel les calculs sont considérés comme l'évaluation de fonctions mathématiques, évitant les changements d'état et les données mutables. Bien que le C++ soit traditionnellement associé à la programmation orientée objet et procédurale, à partir de C++11 et surtout en C++14/17/20, le langage a reçu des outils puissants pour le style fonctionnel. Dans cet article, nous allons examiner les concepts clés qui rendront votre code C++ plus concis, sûr et expressif.
1. Expressions lambda et fermetures
Les expressions lambda sont des fonctions anonymes qui peuvent être utilisées sur place. Elles sont devenues la base de la programmation fonctionnelle en C++. La lambda capture les variables de l'environnement (fermeture) et peut être transmise aux algorithmes STL.
Syntaxe de l'expression lambda
auto lambda = [capture](paramètres) -> type_retour { corps };Exemple : tri avec une lambda
#include <iostream>#include <vector>#include <algorithm>
int main() { std::vector<int> nums = {5, 2, 8, 1, 9}; // Tri décroissant std::sort(nums.begin(), nums.end(), [](int a, int b) { return a > b; }); for (int n : nums) std::cout << n << " "; // 9 8 5 2 1 return 0;}Fermetures : capture par valeur et par référence
#include <iostream>#include <vector>#include <algorithm>
int main() { int threshold = 5; std::vector<int> data = {1, 6, 3, 8, 2}; // Capture par valeur [=] - copie de threshold auto count_greater = std::count_if(data.begin(), data.end(), [=](int x) { return x > threshold; }); // Capture par référence [&] - permet la modification auto modify = [&](int &x) { if (x < threshold) x += threshold; }; std::for_each(data.begin(), data.end(), modify); std::cout << "Count: " << count_greater << ""; // Count: 2 for (int n : data) std::cout << n << " "; // 6 6 8 8 7 return 0;}2. Foncteurs et std::function
Les foncteurs sont des objets de classe qui surchargent l'opérateur operator(). Ils peuvent stocker un état et se comporter comme des fonctions. std::function est un wrapper polymorphe pour stocker n'importe quel objet appelable.
Exemple de foncteur
#include <iostream>
class Adder {private: int base;public: Adder(int b) : base(b) {} int operator()(int x) const { return base + x; }};
int main() { Adder add5(5); std::cout << add5(10) << ""; // 15 std::cout << add5(20) << ""; // 25 return 0;}std::function : wrapper universel
#include <iostream>#include <functional>#include <vector>
void process(const std::vector<int>& data, std::function<bool(int)> predicate) { for (int x : data) { if (predicate(x)) std::cout << x << " "; } std::cout << "";}
int main() { std::vector<int> numbers = {1, 2, 3, 4, 5, 6}; // On peut passer des lambdas process(numbers, [](int n) { return n % 2 == 0; }); // 2 4 6 process(numbers, [](int n) { return n > 3; }); // 4 5 6 // Et des foncteurs struct GreaterThan { int limit; bool operator()(int n) const { return n > limit; } }; process(numbers, GreaterThan{4}); // 5 6 return 0;}3. Algorithmes STL en style fonctionnel
La bibliothèque STL fournit de nombreux algorithmes qui se combinent parfaitement avec les lambdas et les foncteurs. Au lieu de boucles, utilisez std::transf