Je pense que Clang peut être correct.
Selon [lambda.capture] / 11 , une expression id utilisée dans le lambda fait référence au membre capturé par copie de lambda uniquement si elle constitue une utilisation odr . Si ce n'est pas le cas, cela fait référence à l' entité d'origine . Cela s'applique à toutes les versions C ++ depuis C ++ 11.
Selon [basic.dev.odr] / 3 de C ++ 17, une variable de référence n'est pas odr utilisée si l'application de la conversion lvalue-to-rvalue lui donne une expression constante.
Dans le projet C ++ 20, cependant, l'exigence de conversion lvalue-to-rvalue est supprimée et le passage correspondant a été modifié plusieurs fois pour inclure ou non la conversion. Voir CWG numéro 1472 et CWG numéro 1741 , ainsi que CWG numéro 2083 ouvert .
Puisque m
est initialisé avec une expression constante (faisant référence à un objet de durée de stockage statique), son utilisation donne une expression constante par exception dans [expr.const] /2.11.1 .
Ce n'est cependant pas le cas si des conversions lvalue-to-rvalue sont appliquées, car la valeur de n
n'est pas utilisable dans une expression constante.
Par conséquent, selon que les conversions lvalue-to-rvalue doivent ou non être appliquées pour déterminer l'utilisation odr, lorsque vous utilisez m
dans le lambda, cela peut ou non se référer au membre du lambda.
Si la conversion doit être appliquée, GCC et MSVC sont corrects, sinon Clang l'est.
Vous pouvez voir que Clang change son comportement si vous changez l'initialisation de m
pour ne plus être une expression constante:
#include <stdio.h>
#include <functional>
int n = 100;
void g() {}
std::function<int()> f()
{
int &m = (g(), n);
return [m] () mutable -> int {
m += 123;
return m;
};
}
int main()
{
int x = n;
int y = f()();
int z = n;
printf("%d %d %d\n", x, y, z);
return 0;
}
Dans ce cas, tous les compilateurs conviennent que la sortie est
100 223 100
car m
dans le lambda fera référence au membre de la fermeture qui est de type int
initialisé à la copie à partir de la variable de référence m
dans f
.