Ich denke, Clang kann tatsächlich richtig sein.
Nach [lambda.capture] / 11 , eine ID-Expression in dem Lambda verwendete , bezieht sich auf das von kopier erfaßt Mitglied lambda nur , wenn es einen ausmacht ODR-use . Wenn dies nicht der Fall ist, bezieht es sich auf die ursprüngliche Entität . Dies gilt für alle C ++ - Versionen seit C ++ 11.
Gemäß C ++ 17s [basic.dev.odr] / 3 wird eine Referenzvariable nicht odr-verwendet, wenn die Konvertierung von lWert zu rWert einen konstanten Ausdruck ergibt.
Im C ++ 20-Entwurf entfällt jedoch die Anforderung für die Konvertierung von Wert zu Wert, und die entsprechende Passage wurde mehrmals geändert, um die Konvertierung einzuschließen oder nicht einzuschließen. Siehe CWG-Ausgabe 1472 und CWG-Ausgabe 1741 sowie offene CWG-Ausgabe 2083 .
Da m
es mit einem konstanten Ausdruck initialisiert wird (der sich auf ein Objekt mit statischer Speicherdauer bezieht), ergibt die Verwendung einen konstanten Ausdruck pro Ausnahme in [expr.const] /2.11.1 .
Dies ist jedoch nicht der Fall, wenn l-Wert-zu-Wert-Konvertierungen angewendet werden, da der Wert von n
in einem konstanten Ausdruck nicht verwendet werden kann.
Abhängig davon, ob bei der Bestimmung der odr-Verwendung Umrechnungen von lwert zu rwert angewendet werden sollen oder nicht, kann sich dies bei Verwendung m
im Lambda auf das Mitglied des Lambda beziehen oder nicht.
Wenn die Konvertierung angewendet werden soll, sind GCC und MSVC korrekt, andernfalls ist Clang korrekt.
Sie können sehen, dass Clang sein Verhalten ändert, wenn Sie die Initialisierung so ändern m
, dass sie kein konstanter Ausdruck mehr ist:
#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;
}
In diesem Fall stimmen alle Compiler darin überein, dass die Ausgabe ist
100 223 100
denn m
im Lambda wird auf das Mitglied int
des Abschlusses verwiesen, das vom Typ kopiert ist, der aus der Referenzvariablen m
in kopiert wurde f
.