57 votes

Essayer de comprendre les lambdas

Essayer de comprendre Lambda en C ++, voici ce que je ne comprends pas:

 int multiplier = 5;
auto timesFive = [multiplier](int a) { return a * multiplier; }; 
std::cout << timesFive(2) << '\n'; // Prints 10

multiplier = 15;
std::cout << timesFive(2) << '\n'; // Still prints 2*5 == 10 (???) - Should it be 30?
 

Lorsque le programme appelle timesFive() la deuxième fois, je m'attends à un résultat de 30. Mais pourquoi le résultat est-il Still prints 2*5 == 10 et non prints 2*15 == 30 ? Peut-être que la fonction lambda ne peut pas en quelque sorte suivre la valeur de multiplier , même si nous avons déjà essayé de la capturer?

Et quel est le moyen d'obtenir le résultat souhaité?

90voto

Rudi Points 8756

Vous avez capturé multiplier par valeur, ce qui signifie qu'il a été copié dans le lambda. Vous devez le capturer par référence:

 int multiplier = 5;
auto timesFive = [&multiplier](int a) { return a * multiplier; }; 
std::cout << timesFive(2);

multiplier = 15;
std::cout << timesFive(2); 
 

43voto

Yakk Points 31636

Les Lambdas sont syntatic de sucre pour un innommable de la classe et de l'instance de celle-ci. Parfois, l'expansion de votre code pour que cette innommable de la classe peut aider à comprendre ce qui se passe.

[ capture_list ]( arg_list ) -> return_value_clause_opt { body };

devient très grossièrement (pseudo-code):

struct anonymous_type {
  capture_list;
  auto operator()( arg_list ) const -> return_value_clause_opt {
    body
  }
  anonymous_type( capture_list_in ):capture_list(capture_list_in) {}
};

Si vous indiquez une variable en capture_list par le simple nom, il est copié dans une copie au sein de la classe anonyme.

Si votre timesFive est devenu

struct __secret_name__ {
  int multiplier;
  int operator()(int a) const { return a*multiplier; }
};
int multiplier = 5;
auto timesFive = __secret_name__{multiplier};

Il devrait être assez évident que l'évolution multiplier dans le code ci-dessus ne changent pas le comportement de l' timesFive.

Si vous mettez un & devant le nom, un non-const de référence est placé à l'intérieur de la classe anonyme.

struct __secret_name__ {
  int& multiplier;
  int operator()(int a) const { return a*multiplier; }
};
int multiplier = 5;
auto timesFive = __secret_name__{multiplier};

maintenant, l'évolution multiplier va modifier le comportement de l' timesFivecar timesFive détient une référence de multiplicateur, pas une copie.


Quelques détails sauté dessus pour des raisons de concision. Le nom de l' __secret_name__ seulement pour l'exposition. Les variables membres de l'lamba ne sont pas réellement public. Le lambda étant trivialement constructible est de la mise en œuvre définies, même si ses données. Etc.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X