Mengapa Ekspresi Lambda?
Pertimbangkan pernyataan berikut:
int myInt = 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 sedemikian disebut ungkapan lambda. Pertimbangkan juga program pendek berikut:
#sertakanmenggunakan ruang nama std;
int fn (setaraf int)
int jawapan = par + 3;
jawapan balik;
int utama ()
fn (5);
pulangan 0;
Hari ini, adalah mungkin untuk membuat kod fungsi secara khusus dan meletakkannya pada kedudukan argumen 5, panggilan fungsi, fn (5). Fungsi sedemikian 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:
#sertakanmenggunakan ruang nama std;
auto fn = [] (int param)
int jawapan = param + 3;
jawapan balik;
;
int utama ()
pemboleh ubah automatik = fn (2);
cout << variab << '\n';
pulangan 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:
pemboleh ubah automatik = fn (2);Ini bermaksud, fn di luar main (), berakhir sebagai pengecam fungsi. Parameter tersiratnya adalah dari 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 nama std;
batal otherfn (int no1, int (* ptr) (int))
int no2 = (* ptr) (2);
cout << no1 << " << no2 << '\n';
int utama ()
otherfn (4, [] (int param)
int jawapan = param + 3;
jawapan balik;
);
pulangan 0;
Keluarannya adalah:
4 5Terdapat 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 yang 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,
int no2 = (* ptr) (2);Dalam definisi otherfn (), ia memanggil fungsi lambda dengan argumen 2. Nilai kembali panggilan, "(* ptr) (2)" dari fungsi lambda, ditetapkan 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 boleh diberikan kepada pemboleh ubah atau digunakan sebagai argumen untuk panggilan fungsi yang berbeza. Definisi panggilan fungsi 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 dapat 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 penangkapan [], 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 tangkapan [], 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 nama std;
int utama ()
int id = 5;
automatik fn = [id] ()
cout << id << '\n';
;
fn ();
pulangan 0;
Keluarannya adalah 5. Tanpa nama, id, di dalam [], ungkapan lambda tidak akan dapat melihat pemboleh ubah id dari 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, e.g., id di atas, dari ruang lingkup sekitarnya, disediakan 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 nama std;
int utama ()
int id = 5; apungan ft = 2.3; char ch = 'A';
auto fn = [& id, & ft, & ch] ()
id = 6; kaki = 3.4; ch = 'B';
;
fn ();
cout << id << ", " << ft << ", " << ch << '\n';
pulangan 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 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 nama std;
int utama ()
int id = 5; apungan ft = 2.3; char ch = 'A';
automatik fn = [id, ft, ch] ()
// id = 6; kaki = 3.4; ch = 'B';
cout << id << ", " << ft << ", " << ch << '\n';
;
fn ();
id = 6; kaki = 3.4; ch = 'B';
cout << id << ", " << ft << ", " << ch << '\n';
pulangan 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 dapat 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 nama std;
int utama ()
int id = 5; apungan ft = 2.3; char ch = 'A'; bool bl = benar;
auto fn = [id, ft, & ch, & bl] ()
ch = 'B'; bl = palsu;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
pulangan 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 nama std;
int utama ()
int id = 5; apungan ft = 2.3; char ch = 'A'; bool bl = benar;
automatik fn = [&] ()
id = 6; kaki = 3.4; ch = 'B'; bl = palsu;
;
fn ();
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
pulangan 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 nama std;int utama ()
int id = 5; apungan ft = 2.3; char ch = 'A'; bool bl = benar;
automatik fn = [&, id, ft] ()
ch = 'B'; bl = palsu;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
pulangan 0;
Keluarannya adalah:
5, 2.3, B, 0Perhatikan bahawa & bersendirian (i.e., & tidak diikuti oleh pengecam) mesti 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 nama std;
int utama ()
int id = 5; apungan ft = 2.3; char ch = 'A'; bool bl = benar;
automatik fn = [=] ()
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
pulangan 0;
Keluarannya adalah:
5, 2.3, A, 1Nota: = 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 nama std;
int utama ()
int id = 5; apungan ft = 2.3; char ch = 'A'; bool bl = benar;
automatik fn = [=, & ch, & bl] ()
ch = 'B'; bl = palsu;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
pulangan 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 nama std;
output char *;
auto cba = [] (habiskan [])
output = keluar;
;
void prinsipalFunc (input char [], void (* pt) (char []))
(* pt) (input);
cout<<"for principal function"<<'\n';
batal fn ()
cout<<"Now"<<'\n';
int utama ()
input char [] = "untuk fungsi panggilan balik";
prinsipalFunc (input, cba);
fn ();
cout<