Table of Contents

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<class T1, class T2, class transformT>
std::vector<T2> map(const std::vector<T1>& vec, transformT aFunction)
{
  std::vector<T2> 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<int> vect = {1, 2, 3, 4, 5 };
  std::vector<int> 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<class T1, class T2, class transformT>
std::vector<T2> map(const std::vector<T1>& vec, transformT aFunction)
{
  std::vector<T2> result;
  result.reserve(vec.size());
  for(int i = 0; i < vec.size(); i++)
      result.push_back(aFunction(vec[i]);    
}
 
...
  std::vector<int> vect = {1, 2, 3, 4, 5 };
  std::vector<int> vectMultiplyBy2 = map(vect, [](int x) { return x * 2; });
...

Une fonction anonyme se compose donc de trois parties :

Et voilà. C'est le compilateur qui fait le reste du travail…

Maintenant à quoi sert la liste [].

...
  std::vector<int> vect = {1, 2, 3, 4, 5 };
  int bound = 3;
  std::vector<int> 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.