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 mkullanı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 nsabit 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, mlambda ü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 mifadesini 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ü mlambda tipi olan kapatma mekanizmasını en elemanına sevk edecektir içinde intreferans değişkeninden kopya-başlatıldı miçinde f.