61 votes

La redéfinition des lambdas pas autorisé en C++11, pourquoi?

Exemple:

#include <functional>

int main() {
  auto test = []{};
  test = []{};

  return 0;
}

Ce émet le message d'erreur suivant dans gcc 4.7.2:

test.cpp: In function ‘int main()':
test.cpp:5:13: error: no match for ‘operator=' in ‘test = <lambda closure object>main()::<lambda()>{}'
test.cpp:5:13: note: candidate is:
test.cpp:4:16: note: main()::<lambda()>& main()::<lambda()>::operator=(const main()::<lambda()>&) <deleted>
test.cpp:4:16: note:   no known conversion for argument 1 from ‘main()::<lambda()>' to ‘const main()::<lambda()>&'

À partir de la norme 5.1.2.3 (l'emphase est mienne):

Une mise en œuvre peut définir la fermeture type différemment de ce qui est décrit ci-dessous à condition que cela ne modifie pas les comportements observables de l'autre programme que par l'évolution de:

- la taille et/ou l'alignement de la fermeture type,

- si la fermeture est de type trivialement copiable (Clause 9)

- si la fermeture est de type standard-classe de mise en page (Clause 9), ou

- si le type de fermeture est un module de classe (article 9).

Aussi loin que je peux dire, c'est ce que je suis en cours d'exécution. Il est tentant d'utiliser un supprimée opérateur d'affectation et de l'échec. Je suis curieux de savoir si il y a une solution facile, et plus largement de quoi le motiver raison pour permettre la copie constructibility être omis pour les lambdas en général.

69voto

Daniel Frey Points 30752

Vous semblez penser que ces deux lambdas ont le même type, mais ce n'est pas vrai. Chacun crée son propre type:

#include <functional>
#include <type_traits>
#include <iostream>

int main() {
  auto test = []{};
  auto test2 = []{};
  std::cout << std::is_same< decltype( test ), decltype( test2 ) >::value << std::endl;
  return 0;
}

imprime 0. Bien sûr, le message d'erreur que le compilateur pourrait être un peu plus clair en ce qui concerne les...

47voto

Andrew Tomazos Points 18711

Le type de la la lambda-expression (qui est aussi le type de la fermeture de l'objet) est un unique, sans nom, non union type de classe

C'est comme si vous effectuez les opérations suivantes:

struct {} a;
struct {} b;
a = b; // error, type mismatch

Utiliser std::function si vous souhaitez assigner différentes lambdas avec la même signature que la même variable.

std::function<void()> f = []{};
f = []{}; //ok

8voto

J.N. Points 4858

Lambda ne peut pas être redéfinie, car chaque lambda est d'une autre, anonyme, de type incompatible. Ils peuvent être copiés uniquement si vous les transmettre basé sur un modèle de fonction (comme std::function ctor) qui serait en mesure de déduire que le type.

5voto

Rastaban Points 312

La raison pour laquelle vous n'êtes pas en mesure de le faire c'est parce que l'opérateur d'assignation de copie pour le lambda-expression est déclaré supprimé, Voir la section 5.1.2/20 de la norme. Pour un plus clair (pour des définitions de claire) voir cet exemple de code

template<class T> void f(T x1)
{
  T x2 = x1; // copy constructor exists, this operation will succeed.
  x2 = x1; // assignment operator, deleted and will cause an error
}
int main()
{
  f([]{});
  return 0;
}

D'autres réponses ont souligné que chaque lambda a un type unique, mais ce n'est pas la raison pourquoi vous obtenez cette erreur. Cet exemple montre que, même si les deux lambdas ont le même type, il n'est toujours pas en mesure de le copier. Cependant, vous êtes en mesure de le copier dans une nouvelle variable. C'est la raison pour laquelle le message d'erreur est de se plaindre de manquer operator= et non pas sur leurs types différents. Bien que chaque lambda ayant son propre type de contenu ne vous aide pas beaucoup non plus.

2voto

Mark Garcia Points 9851

Si l'on pouvait attribuer un lambda à l'autre lambda d'un type différent, comment faire pour copier la fonction des organes/définitions de qui lambda à l'autre? Si nous voulons être si têtu, alors nous pourrions utiliser certains pays de l' std::function-comme le type à être celui qui va être copié. Mais qui irait à l'encontre de l'ol' C++ règle est de ne pas payer bla bla...

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