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 m
diinisialisasi 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 n
tidak 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 m
di 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 m
menjadi 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 m
dalam lambda akan merujuk ke anggota penutupan yang merupakan jenis int
salin diinisialisasi dari variabel referensi m
di f
.