====== Les fonctions anonymes en C++ ======
===== Pourquoi les fonctions anonymes =====
Souvent nous aimerions pouvoir paramètrer une fonction par un élément de code. Imaginons une fonction qui prendre un tableau d'éléments qui a pour type ''T'' et souhaite appliquer à ces éléments une opération de transformation qui prendrait un élément de type ''T'' et le convertirait en élément de type ''T2''.
Nous pouvons imaginer une telle fonction générique en utilisant des objets.
Nous définissons la fonction ''map'' comme suit :
template
std::vector map(const std::vector& vec, transformT aFunction)
{
std::vector result;
result.reserve(vec.size());
for(int i = 0; i < vec.size(); i++)
result.push_back(aFunction(vec[i]);
}
Nous pouvons donc définir la transformation suivante
struct multiplyBy2
{
int operator(int aValue) { return aValue * 2; }
};
Et dès lors :
std::vector vect = {1, 2, 3, 4, 5 };
std::vector vectMultiplyBy2 = map(vect, multiplyBy2());
appellera pour chacun des éléments de ''vect'' la function ''int operator(int aValue)'' de l'objet ''multiplyBy2''.
Donc nous pouvons encapsuler des fonctions dans des objets et utiliser ces objets pour passer du code à exécuter à une autre fonction. Cependant, ce n'est pas très lisible et intuitif.
===== Les fonctions anonymes en C++ =====
C++ a introduit avec la version C++11 une syntaxe pour faire le travail précédent à votre place. En fait, le fonctionnement est toujours le même que celui précédemment décrit mais c'est le compilateur qui fait le travail et non plus vous.
Donc quand j'écris la fonction ''map'', je vais pouvoir écrire toujours la fonction de la même manière, mais je vais passer en paramètre non plus un constructeur sur l'objet qui implante la fonction mais directement la fonction :
template
std::vector map(const std::vector& vec, transformT aFunction)
{
std::vector result;
result.reserve(vec.size());
for(int i = 0; i < vec.size(); i++)
result.push_back(aFunction(vec[i]);
}
...
std::vector vect = {1, 2, 3, 4, 5 };
std::vector vectMultiplyBy2 = map(vect, [](int x) { return x * 2; });
...
Une fonction anonyme se compose donc de trois parties :
* [] : il s'agit de la liste des variables auxquelles on souhaite accéder. Par défaut, dans le corps d'une fonction, nous n'accédons qu'aux variables locales à la fonction et aux paramètres. Cependant, il est possible d'accéder aux variables dans le contexte d'appel.
* (int x) : il s'agit de la liste des paramètres de la fonction.
* { return x * 2; } : il s'agit du corps de la fonction qui contient le code de la fonction qui sera exécuté.
Et voilà. C'est le compilateur qui fait le reste du travail...
Maintenant à quoi sert la liste ''[]''.
...
std::vector vect = {1, 2, 3, 4, 5 };
int bound = 3;
std::vector vectModuloValue = map(vect, [bound](int x) { return x % bound; });
...
Cela sert à indiquer que l'on souhaite accéder à la valeur ''bound'' qui a été définie et qui est un paramètre de la fonction. Si ''bound'' n'était pas indiqué dans la liste des paramètres, le code ne pourrait pas compiler parce que ''bound'' est défini à l'exérieur de la fonction. Quand vous indiquez que vous allez utiliser ''bound'', le compilateur va considérer que ''bound'' est lié à la fonction.