Lambda expressions en C++

Premier exemple

Voici un exemple d'une fonction qui trie selon la valeur absolue des nombres :

#include <algorithm>
#include <cmath>

void abssort(float* x, unsigned n) {
    std::sort(x, x + n,
        [](float a, float b) {
            return (std::abs(a) < std::abs(b));
        }
    );
}

Le [] qui débute la lambda-expression s'appelle clause de capture ou introduction lambda. IL permet en tout cas de dire que la suite est une lambda expression.

Capture de variables

[]

[] que l'on ne peut pas utiliser de variables du scope d'au dessus. Le code suivant ne compile pas car on utilise y dans le corps de f.

int y = 1;
auto f = [](int x) -> int {return x+y;};
printf("%d", f(2));

Capture par valeur

Qu'affiche le programme suivant ?

int y = 1;
auto f = [y](int x) -> int {return x+y;};
y = 2000;
printf("%d", f(2));

Il affiche 3 car on a capturé la valeur de y au moment on a écrit la lambda expression.

Capture par référence

Pour réaliser une capture par référence, on utilise [&y]. Qu'affiche le programme suivant ?

int y = 1;
auto f = [&y](int x) -> int {return x+y;};
y = 1000;
printf("%d", f(2));

Il affiche 1002 car on a capturé la valeur de y par référence. Quand on appelle f(2), on regarde la valeur de y.

On peut mélanger

Bien sûr, on peut mélanger de la capture par valeur et par référence. Par exemple :

[&y, z](int x) -> int {return x+y+z;}

Applications

TODO: trouver un exemple pertinent

Fonctions en Javascript

Javascript a un comportement spécial avec le mot-clé this qui désigne un objet contexte. Pour une fonction déclarée au plus haut niveau, this désigne un objet global globalThis, typiquement la fenêtre du navigateur :

function f() {
    // this est globalThis
}

Mais en mode strict, c'est undefined...

En englobant des fonctions c'est pareil :

function f() {
  function g() {
    return this;
  }
  return g();
} 

L'appelle à f() renvoie globalThis.

Dans une classe, this est l'objet courant.

class A {
  f() {
    // this ici désigne l'instance de A
  }
}
class B {
  f() {
    function g() {
        return this; // ici this est undefined
    }
    return g();
  }
}

Par contre, avec une fonction flèche, le this est conservé :

class C {
  f() {
    const g = () => this; // ici this est l'instance de C
    return g();
  }
}