Saya pikir Dentang mungkin benar.
Menurut [lambda.capture] / 11 , ekspresi-id yang digunakan dalam lambda mengacu pada anggota yang diambil oleh-lambda hanya jika itu merupakan penggunaan odr . Jika tidak, maka mengacu pada entitas asli . Ini berlaku untuk semua versi C ++ sejak C ++ 11.
Menurut C ++ 17 [basic.dev.odr] / 3 variabel referensi tidak digunakan jika menggunakan konversi lvalue-ke-rvalue akan menghasilkan ekspresi yang konstan.
Namun dalam konsep C ++ 20 persyaratan untuk konversi nilai-ke-nilai turun dan bagian yang relevan diubah beberapa kali untuk menyertakan atau tidak menyertakan konversi. Lihat masalah CWG 1472 dan masalah CWG 1741 , serta masalah CWG terbuka 2083 .
Karena mdiinisialisasi dengan ekspresi konstan (merujuk ke objek durasi penyimpanan statis), menggunakannya menghasilkan ekspresi konstan per pengecualian dalam [expr.const] /2.11.1 .
Namun, ini bukan masalahnya jika konversi nilai-ke-nilai diterapkan, karena nilai ntidak dapat digunakan dalam ekspresi konstan.
Oleh karena itu, tergantung pada apakah konversi nilai-ke-nilai atau tidak seharusnya diterapkan dalam menentukan penggunaan odr, ketika Anda menggunakannya mdi lambda, itu mungkin merujuk pada anggota lambda atau tidak.
Jika konversi harus diterapkan, GCC dan MSVC sudah benar, jika tidak, Dentang adalah.
Anda dapat melihat bahwa Dentang mengubah perilaku itu jika Anda mengubah inisialisasi mmenjadi tidak ekspresi konstan lagi:
#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;
}
Dalam hal ini semua kompiler setuju bahwa outputnya adalah
100 223 100
karena mdalam lambda akan merujuk ke anggota penutupan yang merupakan jenis intsalin diinisialisasi dari variabel referensi mdi f.