Saya memahami cara yang benar untuk menangkap this
(untuk mengubah properti objek) di lambda adalah sebagai berikut:
auto f = [this] () { /* ... */ };
Tapi saya penasaran dengan keanehan berikut yang pernah saya lihat:
class C {
public:
void foo() {
// auto f = [] () { // this not captured
auto f = [&] () { // why does this work?
// auto f = [&this] () { // Expected ',' before 'this'
// auto f = [this] () { // works as expected
x = 5;
};
f();
}
private:
int x;
};
Keanehan yang membuat saya bingung (dan ingin dijawab) adalah mengapa berikut ini berhasil:
auto f = [&] () { /* ... */ }; // capture everything by reference
Dan mengapa saya tidak bisa secara eksplisit menangkap this
dengan referensi:
auto f = [&this] () { /* ... */ }; // a compiler error as seen above.
this
tidak dapat diubah, itu tidak cukup besar untuk membuat referensi lebih cepat ... dan bagaimanapun , itu tidak benar-benar ada , jadi itu telah tidak ada kehidupan nyata, yang berarti referensi apa pun padanya akan tergantung menurut definisi.this
adalah nilai pr, bukan lvalue.Jawaban:
Alasan
[&this]
tidak berhasil adalah karena ini adalah kesalahan sintaks. Setiap parameter yang dipisahkan koma dilambda-introducer
is acapture
:capture: identifier & identifier this
Anda dapat melihat itu
&this
tidak diperbolehkan secara sintaksis. Alasan itu tidak diizinkan adalah karena Anda tidak ingin menangkapthis
dengan referensi, karena ini adalah penunjuk const kecil. Anda hanya ingin meneruskannya berdasarkan nilai - jadi bahasanya tidak mendukung penangkapanthis
dengan referensi.Untuk menangkap
this
secara eksplisit Anda dapat menggunakan[this]
filelambda-introducer
.Yang pertama
capture
bisa jadicapture-default
adalah:capture-default: & =
Ini berarti menangkap secara otomatis apa pun yang saya gunakan, masing-masing dengan referensi (
&
) atau dengan nilai (=
) - namun perlakuannyathis
khusus - dalam kedua kasus itu ditangkap oleh nilai untuk alasan yang diberikan sebelumnya (bahkan dengan tangkapan default&
, yang biasanya berarti ditangkap dengan referensi).5.1.2.7/8:
Jadi lambda bertindak seolah-olah itu adalah bagian dari fungsi anggota yang melingkupi saat menggunakan nama anggota (seperti dalam contoh Anda, penggunaan nama
x
), sehingga akan menghasilkan "penggunaan implisit"this
seperti fungsi anggota.Sehingga Anda dapat menggunakan
[this]
,[&]
,[=]
atau[&,this]
sebagailambda-introducer
untuk menangkapthis
pointer dengan nilai.Namun
[&this]
dan[=, this]
berbentuk buruk. Dalam kasus terakhir, gcc dengan memaafkan memperingatkan hal[=,this]
ituexplicit by-copy capture of ‘this’ redundant with by-copy capture default
daripada kesalahan.sumber
[&]
jika Anda melakukan sesuatu seperti membuat blok untuk diteruskan ke struktur kontrol", tetapi secara eksplisit menangkap jika Anda memproduksi lambda yang akan digunakan untuk tujuan yang kurang sederhana.[&]
adalah ide yang buruk jika lambda akan hidup lebih lama dari jangkauan saat ini. Namun, banyak penggunaan lambda hanyalah cara untuk meneruskan blok ke struktur kontrol, dan blok tidak akan hidup lebih lama dari blok yang dibuat dalam cakupannya.this
adalah kata kunci,this
bukan pengenal.Karena standar tidak ada
&this
dalam daftar Captures:N4713 8.4.5.2 Penangkapan:
lambda-capture: capture-default capture-list capture-default, capture-list capture-default: & = capture-list: capture...opt capture-list, capture...opt capture: simple-capture init-capture simple-capture: identifier &identifier this * this init-capture: identifier initializer &identifier initializer
Jadi, jaminan standar
this
dan*this
valid, dan&this
tidak valid. Juga, menangkapthis
berarti menangkap*this
(yang merupakan nilai l, objek itu sendiri) dengan referensi , daripada menangkapthis
penunjuk dengan nilai !sumber
*this
menangkap objek berdasarkan nilai