Mengapa Lambda Expression?
Pertimbangkan pernyataan berikut:
intmyInt= 52;Di sini, myInt adalah pengecam, nilai. 52 adalah harfiah, nilai. Hari ini, adalah mungkin untuk membuat kod fungsi secara khusus dan meletakkannya pada kedudukan 52. Fungsi seperti itu disebut ungkapan lambda. Pertimbangkan juga program pendek berikut:
#sertakan
menggunakan ruang namaJam;
intfn(intmelalui)
{
intjawapan=melalui+ 3;
kembalijawapan;
}
intutama()
{
fn(5);
kembali 0;
}
Hari ini, adalah mungkin untuk membuat kod fungsi secara khusus dan meletakkannya pada kedudukan argumen 5, panggilan fungsi, fn (5). Fungsi seperti itu disebut ungkapan lambda. Ungkapan lambda (fungsi) dalam kedudukan itu adalah nilai.
Sebarang literal kecuali literal string adalah prvalue. Ekspresi lambda adalah reka bentuk fungsi khas yang sesuai dengan literal dalam kod. Ini adalah fungsi tanpa nama (tanpa nama). Artikel ini menerangkan ungkapan utama C ++ baru, yang disebut ungkapan lambda. Pengetahuan asas dalam C ++ adalah syarat untuk memahami artikel ini.
Kandungan Artikel
- Ilustrasi Lambda Expression
- Bahagian Ekspresi Lambda
- Tangkapan
- Skema Fungsi Panggilan Balik Klasik dengan Lambda Expression
- Jenis trailing-return
- Penutupan
- Kesimpulannya
Ilustrasi Lambda Expression
Dalam program berikut, fungsi, yang merupakan ekspresi lambda, diberikan kepada pemboleh ubah:
#sertakan
menggunakan ruang namaJam;
keretafn= [](intberhenti)
{
intjawapan=berhenti+ 3;
kembalijawapan;
};
intutama()
{
keretavariab=fn(2);
kos <<variab<< ' n';
kembali 0;
}
Keluarannya adalah:
5Di luar fungsi utama (), terdapat pemboleh ubah, fn. Jenisnya adalah automatik. Secara automatik dalam keadaan ini bermaksud bahawa jenis sebenar, seperti int atau float, ditentukan oleh operan kanan pengendali tugasan (=). Di sebelah kanan pengendali tugasan terdapat ungkapan lambda. Ungkapan lambda adalah fungsi tanpa jenis pengembalian sebelumnya. Perhatikan penggunaan dan kedudukan tanda kurung persegi, []. Fungsi mengembalikan 5, int, yang akan menentukan jenis untuk fn.
Dalam fungsi utama (), terdapat pernyataan:
keretavariab=fn(2);Ini bermaksud, fn di luar main (), berakhir sebagai pengecam fungsi. Parameter tersiratnya adalah ungkapan lambda. Jenis pemboleh ubah adalah automatik.
Perhatikan bahawa ungkapan lambda diakhiri dengan titik koma, sama seperti definisi kelas atau struktur, diakhiri dengan titik koma.
Dalam program berikut, fungsi, yang merupakan ungkapan lambda yang mengembalikan nilai 5, adalah argumen untuk fungsi lain:
#sertakanmenggunakan ruang namaJam;
batallain-lain(intno1,int (*ptr)(int))
{
intno2= (*ptr)(2);
kos <<no1<< '' <<no2<< ' n';
}
intutama()
{
lain-lain(4,[](intberhenti)
{
intjawapan=berhenti+ 3;
kembalijawapan;
});
kembali 0;
}
Keluarannya adalah:
Empat limaTerdapat dua fungsi di sini, ungkapan lambda dan fungsi lain (). Ungkapan lambda adalah argumen kedua dari lainfn (), disebut dalam utama (). Perhatikan bahawa fungsi lambda (ungkapan) tidak berakhir dengan titik koma dalam panggilan ini kerana, di sini, ia adalah argumen (bukan fungsi berdiri sendiri).
Parameter fungsi lambda dalam definisi fungsi otherfn () adalah penunjuk kepada fungsi. Penunjuk mempunyai nama, ptr. Nama, ptr, digunakan dalam definisi otherfn () untuk memanggil fungsi lambda.
Penyataan,
intno2= (*ptr)(2);Dalam definisi otherfn (), ia memanggil fungsi lambda dengan argumen 2. Nilai kembali panggilan, '(* ptr) (2)' dari fungsi lambda, ditugaskan ke no2.
Program di atas juga menunjukkan bagaimana fungsi lambda dapat digunakan dalam skema fungsi panggilan balik C ++.
Bahagian Ekspresi Lambda
Bahagian fungsi lambda khas adalah seperti berikut:
[] () {}- [] adalah klausa tangkapan. Ia boleh mempunyai barang.
- () adalah untuk senarai parameter.
- {} adalah untuk badan fungsi. Sekiranya fungsinya berdiri sendiri, maka ia harus diakhiri dengan titik koma.
Tangkapan
Definisi fungsi lambda dapat diberikan kepada pemboleh ubah atau digunakan sebagai argumen untuk panggilan fungsi yang berbeza. Definisi untuk fungsi panggilan seperti itu harus memiliki parameter, penunjuk ke fungsi, sesuai dengan definisi fungsi lambda.
Definisi fungsi lambda berbeza dengan definisi fungsi normal. Ia boleh diberikan kepada pemboleh ubah dalam skop global; fungsi ini ditugaskan ke pemboleh ubah juga boleh dikodkan di dalam fungsi lain. Apabila ditugaskan ke pemboleh ubah skop global, badannya dapat melihat pemboleh ubah lain dalam skop global. Apabila ditugaskan pada pemboleh ubah dalam definisi fungsi normal, badannya dapat melihat pemboleh ubah lain dalam ruang lingkup fungsi hanya dengan bantuan klausa penangkapan, [].
Klausa tangkapan [], juga dikenal sebagai pengantar lambda, membolehkan pemboleh ubah dihantar dari ruang lingkup (fungsi) sekitarnya ke dalam badan fungsi ekspresi lambda. Badan fungsi ekspresi lambda dikatakan menangkap pemboleh ubah ketika menerima objek. Tanpa klausa penangkapan [], pemboleh ubah tidak dapat dikirim dari ruang lingkup sekitarnya ke badan fungsi ekspresi lambda. Program berikut menggambarkan ini, dengan skop fungsi () utama, seperti skop sekitarnya:
#sertakanmenggunakan ruang namaJam;
intutama()
{
intID= 5;
keretafn= [ID]()
{
kos <<ID<< ' n';
};
fn();
kembali 0;
}
Keluarannya adalah 5 . Tanpa nama, id, di dalam [], ungkapan lambda tidak akan dapat melihat pemboleh ubah id dari skop fungsi utama ().
Menangkap dengan Rujukan
Contoh penggunaan klausa tangkapan di atas adalah menangkap berdasarkan nilai (lihat perincian di bawah). Dalam menangkap dengan rujukan, lokasi (penyimpanan) pemboleh ubah, mis., Id di atas, dari ruang lingkup sekitarnya, tersedia di dalam badan fungsi lambda. Jadi, mengubah nilai pemboleh ubah di dalam badan fungsi lambda akan mengubah nilai pemboleh ubah yang sama dalam ruang lingkup sekitarnya. Setiap pemboleh ubah yang diulang dalam klausa tangkapan didahului oleh ampersand (&) untuk mencapainya. Program berikut menggambarkan ini:
#sertakanmenggunakan ruang namaJam;
intutama()
{
intID= 5; terapungkaki= 2.3; charch= 'KE';
keretafn= [&ID,&kaki,&ch]()
{
ID= 6;kaki= 3.4;ch= 'B';
};
fn();
kos <<ID<< ',' <<kaki<< ',' <<ch<< ' n';
kembali 0;
}
Keluarannya adalah:
6, 3.4, BMengesahkan bahawa nama pemboleh ubah di dalam badan fungsi ekspresi lambda adalah untuk pemboleh ubah yang sama di luar ungkapan lambda.
Menangkap mengikut Nilai
Dalam menangkap berdasarkan nilai, salinan lokasi pemboleh ubah, dari ruang lingkup sekitarnya, tersedia di dalam badan fungsi lambda. Walaupun pemboleh ubah di dalam badan fungsi lambda adalah salinan, nilainya tidak dapat diubah di dalam badan seperti sekarang. Untuk mencapai tangkapan berdasarkan nilai, setiap pemboleh ubah yang diulang dalam klausa tangkapan tidak didahului oleh apa-apa. Program berikut menggambarkan ini:
#sertakanmenggunakan ruang namaJam;
intutama()
{
intID= 5; terapungkaki= 2.3; charch= 'KE';
keretafn= [id, kaki, ch]()
{
// id = 6; ft = 3.4; ch = 'B';
kos <<ID<< ',' <<kaki<< ',' <<ch<< ' n';
};
fn();
ID= 6;kaki= 3.4;ch= 'B';
kos <<ID<< ',' <<kaki<< ',' <<ch<< ' n';
kembali 0;
}
Keluarannya adalah:
5, 2.3, A6, 3.4, B
Sekiranya penunjuk komen dikeluarkan, program tidak akan disusun. Penyusun akan mengeluarkan mesej ralat bahawa pemboleh ubah di dalam definisi badan fungsi ungkapan lambda tidak dapat diubah. Walaupun pemboleh ubah tidak dapat diubah di dalam fungsi lambda, mereka boleh diubah di luar fungsi lambda, seperti yang ditunjukkan oleh output program di atas.
Mencampurkan Tangkapan
Menangkap dengan rujukan dan menangkap dengan nilai dapat dicampur, seperti yang ditunjukkan oleh program berikut:
#sertakanmenggunakan ruang namaJam;
intutama()
{
intID= 5; terapungkaki= 2.3; charch= 'KE'; boolbl= benar;
keretafn= [id, kaki,&ch,&bl]()
{
ch= 'B';bl= salah;
kos <<ID<< ',' <<kaki<< ',' <<ch<< ',' <<bl<< ' n';
};
fn();
kembali 0;
}
Keluarannya adalah:
5, 2.3, B, 0Apabila semua ditangkap, adalah dengan rujukan:
Sekiranya semua pemboleh ubah yang akan ditangkap ditangkap dengan rujukan, maka hanya satu & akan mencukupi dalam klausa tangkapan. Program berikut menggambarkan ini:
#sertakanmenggunakan ruang namaJam;
intutama()
{
intID= 5; terapungkaki= 2.3; charch= 'KE'; boolbl= benar;
keretafn= [&]()
{
ID= 6;kaki= 3.4;ch= 'B';bl= salah;
};
fn();
kos <<ID<< ',' <<kaki<< ',' <<ch<< ',' <<bl<< ' n';
kembali 0;
}
Keluarannya adalah:
6, 3.4, B, 0Sekiranya beberapa pemboleh ubah ditangkap dengan rujukan dan yang lain berdasarkan nilai, maka satu & akan mewakili semua rujukan, dan selebihnya tidak akan didahului oleh apa-apa, seperti yang ditunjukkan oleh program berikut:
menggunakan ruang namaJam;intutama()
{
intID= 5; terapungkaki= 2.3; charch= 'KE'; boolbl= benar;
keretafn= [&, id, kaki]()
{
ch= 'B';bl= salah;
kos <<ID<< ',' <<kaki<< ',' <<ch<< ',' <<bl<< ' n';
};
fn();
kembali 0;
}
Keluarannya adalah:
5, 2.3, B, 0Perhatikan bahawa & bersendirian (iaitu, & tidak diikuti oleh pengecam) harus menjadi watak pertama dalam klausa tangkapan.
Apabila semua ditangkap, berdasarkan nilai:
Sekiranya semua pemboleh ubah yang akan ditangkap ditangkap berdasarkan nilai, maka hanya satu = yang mencukupi dalam klausa tangkapan. Program berikut menggambarkan ini:
#sertakanmenggunakan ruang namaJam;
intutama()
{
intID= 5; terapungkaki= 2.3; charch= 'KE'; boolbl= benar;
keretafn= [=]()
{
kos <<ID<< ',' <<kaki<< ',' <<ch<< ',' <<bl<< ' n';
};
fn();
kembali 0;
}
Keluarannya adalah:
5, 2.3, A, 1Catatan : = hanya boleh dibaca, mulai sekarang.
Sekiranya beberapa pemboleh ubah ditangkap oleh nilai dan yang lain dengan rujukan, maka satu = akan mewakili semua pemboleh ubah yang disalin hanya baca, dan selebihnya masing-masing akan mempunyai &, seperti yang ditunjukkan oleh program berikut:
#sertakanmenggunakan ruang namaJam;
intutama()
{
intID= 5; terapungkaki= 2.3; charch= 'KE'; boolbl= benar;
keretafn= [=,&ch,&bl]()
{
ch= 'B';bl= salah;
kos <<ID<< ',' <<kaki<< ',' <<ch<< ',' <<bl<< ' n';
};
fn();
kembali 0;
}
Keluarannya adalah:
5, 2.3, B, 0Perhatikan bahawa = sahaja harus menjadi watak pertama dalam klausa tangkapan.
Skema Fungsi Panggilan Balik Klasik dengan Lambda Expression
Program berikut menunjukkan bagaimana skema fungsi panggilan balik klasik dapat dilakukan dengan ungkapan lambda:
#sertakanmenggunakan ruang namaJam;
char *pengeluaran;
keretacba= [](charkeluar[])
{
pengeluaran=keluar;
};
batalmainFunc(charinput[],batal (*untuk)(char[]))
{
(*untuk)(input);
kos<<'untuk fungsi pokok'<<' n';
}
batalfn()
{
kos<<'Sekarang'<<' n';
}
intutama()
{
charinput[] = 'untuk fungsi panggilan balik';
mainFunc(input, cba);
fn();
kos<<pengeluaran<<' n';
kembali 0;
}
Keluarannya adalah:
untuk fungsi pokokSekarang
untuk fungsi panggilan balik
Ingatlah bahawa apabila definisi ekspresi lambda diberikan kepada pemboleh ubah dalam skop global, badan fungsinya dapat melihat pemboleh ubah global tanpa menggunakan klausa tangkapan.
Jenis trailing-return
Jenis pengembalian ekspresi lambda adalah automatik, yang bermaksud penyusun menentukan jenis kembali dari ungkapan kembali (jika ada). Sekiranya pengaturcara benar-benar ingin menunjukkan jenis pengembalian, maka dia akan melakukannya seperti dalam program berikut:
#sertakanmenggunakan ruang namaJam;
keretafn= [](intberhenti) -> int
{
intjawapan=berhenti+ 3;
kembalijawapan;
};
intutama()
{
keretavariab=fn(2);
kos <<variab<< ' n';
kembali 0;
}
Keluarannya adalah 5. Setelah senarai parameter, operator anak panah diketik. Ini diikuti oleh jenis pengembalian (int dalam kes ini).
Penutupan
Pertimbangkan segmen kod berikut:
strukturCla{
intID= 5;
charch= 'ke';
}obj1, obj2;
Di sini, Cla adalah nama kelas struct. Obj1 dan obj2 adalah dua objek yang akan ditunjukkan dari kelas struct. Ekspresi lambda serupa dalam pelaksanaannya. Definisi fungsi lambda adalah sejenis kelas. Apabila fungsi lambda disebut (dipanggil), suatu objek dibuat berdasarkan definisi. Objek ini dipanggil penutupan. Penutupan inilah yang melakukan kerja yang diharapkan oleh lambda.
Walau bagaimanapun, pengekodan ungkapan lambda seperti struktur di atas akan mempunyai obj1 dan obj2 digantikan oleh argumen parameter yang sesuai. Program berikut menggambarkan ini:
#sertakanmenggunakan ruang namaJam;
keretafn= [](intparam1,intparam2)
{
intjawapan=param1+param2;
kembalijawapan;
} (2,3);
intutama()
{
keretadi mana=fn;
kos <<di mana<< ' n';
kembali 0;
}
Keluarannya adalah 5. Argumen adalah 2 dan 3 dalam kurungan. Perhatikan bahawa panggilan fungsi ekspresi lambda, fn, tidak mengambil argumen kerana argumen telah dikodkan pada akhir definisi fungsi lambda.
Kesimpulannya
Ungkapan lambda adalah fungsi tanpa nama. Ia ada dalam dua bahagian: kelas dan objek. Takrifnya adalah jenis kelas. Apabila ungkapan disebut, objek terbentuk dari definisi. Objek ini dipanggil penutupan. Penutupan inilah yang melakukan kerja yang diharapkan oleh lambda.
Agar ungkapan lambda menerima pemboleh ubah dari skop fungsi luar, ia memerlukan klausa penangkapan yang tidak kosong ke badan fungsinya.