Bence Clang aslında doğru olabilir.
Göre [lambda.capture] / 11 , bir kimlik-sentezleme bir teşkil yalnızca lambda kullanılan Lambda ile kopye yakalanan elemanına değinmektedir ODR kullanımını . Değilse, orijinal varlığı ifade eder . Bu, C ++ 11'den beri tüm C ++ sürümleri için geçerlidir.
C ++ 17'nin [basic.dev.odr] / 3'e göre, bir referans değişken, lvalve -rvalue dönüşümü uygulandığında sabit bir ifade verirse odr kullanılmaz.
Ancak C ++ 20 taslağında, lvalue-rvalue dönüşümü için gereksinim bırakılır ve ilgili geçiş, dönüşümü dahil etmek veya içermemek için birkaç kez değiştirilir. Bkz. CWG sayı 1472 ve CWG sayı 1741 ve ayrıca açık CWG sayı 2083 .
Yana m
kullanılarak (statik depolama süresi nesneye atıfta) sabit bir ifade ile başlatılır Bu özel durum başına sabit bir ifade verir [expr.const] /2.11.1 .
Değer değeri n
sabit bir ifadede kullanılamadığından , değer-değer-değer dönüşümleri uygulanırsa durum böyle değildir.
Bu nedenle, odda kullanımının belirlenmesinde lvalue-rvalue dönüşümlerinin uygulanıp uygulanmayacağına bağlı olarak, lambda'da kullandığınızda, m
lambda üyesine işaret edebilir veya etmeyebilir.
Dönüştürmenin uygulanması gerekiyorsa, GCC ve MSVC doğrudur, aksi takdirde Clang doğrudur.
Artık ilk m
ifadesini sabit bir ifade olmayacak şekilde değiştirirseniz Clang'ın davranışını değiştirdiğini görebilirsiniz :
#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;
}
Bu durumda tüm derleyiciler çıktının
100 223 100
çünkü m
lambda tipi olan kapatma mekanizmasını en elemanına sevk edecektir içinde int
referans değişkeninden kopya-başlatıldı m
içinde f
.