auto foo = "You're using g++!";
auto compiler_detector = [foo](auto foo) { std::puts(foo); };
compiler_detector("You're using clang++!");
clang ++ 3.6.0 et plus récent imprimer "Vous utilisez clang ++!" et avertir que la capture
foo
n'est pas utilisée.g ++ 4.9.0 et plus récent imprimer "Vous utilisez g ++!" et avertir que le paramètre
foo
n'est pas utilisé.
Quel compilateur suit plus précisément la norme C ++ ici?
struct Lambda { template<typename T> void operator()(T foo) const { /* ... */ } private: decltype(outer_foo) foo{outer_foo}; }
.Réponses:
Mise à jour: comme promis par le président Core dans la citation du bas, le code est maintenant mal formé :
Il y a quelques temps, il y a eu quelques problèmes concernant la recherche de nom dans lambdas. Ils ont été résolus par N2927 :
La recherche est toujours effectuée dans le contexte de l' expression lambda , jamais «après» la transformation en corps de fonction membre d'un type de fermeture. Voir [expr.prim.lambda] / 8 :
(L'exemple montre également clairement que la recherche ne considère pas en quelque sorte le membre de capture généré du type de fermeture.)
Le nom
foo
n'est pas (re) déclaré dans la capture; il est déclaré dans le bloc contenant l'expression lambda. Le paramètrefoo
est déclaré dans un bloc imbriqué dans ce bloc externe (voir [basic.scope.block] / 2 , qui mentionne également explicitement les paramètres lambda). L'ordre de recherche va clairement des blocs internes aux blocs externes . Par conséquent, le paramètre doit être sélectionné, c'est-à-dire que Clang a raison.Si vous deviez faire de la capture un init-capture, c'est-à-dire
foo = ""
au lieu defoo
, la réponse ne serait pas claire. En effet, la capture induit désormais une déclaration dont le "bloc" n'est pas donné. J'ai envoyé un message à la chaise principale à ce sujet, qui a répondula source
J'essaie de rassembler quelques commentaires sur la question pour vous donner une réponse significative.
Tout d'abord, notez que:
foo
Par conséquent, la logique me ferait dire au premier coup d'œil que le paramètre devrait masquer la variable capturée comme dans:
Quoi qu'il en soit, @nm a correctement noté que les membres de données non statiques déclarés pour les variables capturées par copie ne sont en fait pas nommés. Cela étant dit, le membre de données sans nom est toujours accessible au moyen d'un identificateur (c'est-à-dire
foo
). Par conséquent, le nom du paramètre de l'opérateur d'appel de fonction doit toujours (laissez-moi dire) masquer cet identificateur .Comme l'a correctement souligné @nm dans les commentaires de la question:
À cause de cela, je dirais que le bruit est juste.
la source