On continue l’aventure Cplusplus11 après le premier article qui était plus une mise ne jambe. Cette fois-ci nous allons attaquer les fonctions anonymes, Lambda expression. Les expressions lambda sont utiles pour écrire des blocs de code en ligne qui sont des fonctions un peu spéciales. Ces fonctions anonymes peuvent être passées en paramètre d’autres fonctions et peuvent aussi récupérer le contexte comme nous le verrons plus loin. Par ailleurs les fonctions lambda améliorent aussi la lisibilité des programmes C++11 car il n’est plus nécessaire d’encapsuler des méthodes qu’on veut utiliser qu’une fois dans des classes ou des fichiers externes. C’est maintenant l’heure d’explorer la signature des Lambda expression.
Signature d’une expression lambda
[capture] (arguments) attribute-specifier mutable exception-specification -> return-type {body}
// or
[capture] (arguments) -> return-type {body}
// or
[capture] (arguments) {body}
// or
[capture] {body}
Description de la signature de l’expression lambda
- capture (liste de capture)
-
- [] : aucune capture des variables du contexte
- [this] : capture le pointeur this de la classe englobante
- [&] : capture toutes les variables du contexte par référence
- [=] : capture toutes les variables du contexte par valeur
- [&x] : capture uniquement la variable x par référence
- [x] : capture uniquement la variable x par par valeur
- [x, &y] : capture la variable x par par valeur et y par référence
- arguments (liste d’arguments)
-
- liste des paramètres de la fonction lambda
- attribute-specifier, mutable, exception-specification (modificateur et spécificateurs)
-
- attribute-specifier : [[noreturn]] indique que la fonction ne retourne rien et [[carries_dependency]] permet de contrôler la gestion du stockage en mémoire. Ne fonctionne pas avec G++ 4.6.3, actuellement seul Intel-C++ 12.1 les supportes
- mutable : permet de modifier les variables capturées par valeur dans le corps de la fonction
- exception-specification : spécificateur d’exception tel que noexcept, throw(), etc…
- return-type
- Type de retour de la fonction lambda.
- body
- Corps de la fonction lambda.
Exemple d’utilisation (projet github des exemples)
#include<iostream>
#include<vector>
#include<algorithm>
int main() {
std::vector<std::string> data{"first", "second", "third"};
std::string one = "one!!";
std::string two = "two";
std::string three = "three";
std::cout << std::endl;
// Process data vector with lambda function
for_each(begin(data), end(data), [one, &two, &three](std::string &item) mutable {
item += "_append";
one += "_another value now"; // We use "mutable" for variable passed by copy.
two += "_two";
three += "_three";
});
// Print data vector after processing
std::cout << "after:" << std::endl << " - data: ";
for (const auto d : data) {
std::cout << d << " ";
}
std::cout << std::endl;
std::cout << " - one: " << one << " - two: " << two << " - three: " << three;
std::cout << std::endl;
return 0;
}
Dans cet exemple nous initialisons un vecteur de string avec 3 éléments, puis nous initialisons 3 variables de type string. Nous utilisons for_each pour parcourir le vecteur data et concaténons chaque élément avec une expression lambda passée en paramètre de for_each. Dans le corps de la fonction lambda, nous concaténons aussi les variables one (récupéré par valeur), two (récupéré par référence), three (récupéré par référence). Nous affichons, au final, le résultat. Vous remarquerez que la variable one n’a pas été impactée après le traitement car elle a été capturée par valeur.
//output after: - data: first_append second_append third_append - one: one!! - two: two_two_two_two - three: three_three_three_three
Ce sera tout pour le moment, nous attaquerons d’autres nouveautés dans un prochain article…

