Ekspresi Lambda dalam C ++

Lambda Expressions C



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

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:

5

Di 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:

#sertakan

menggunakan 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 lima

Terdapat 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:

#sertakan

menggunakan 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:

#sertakan

menggunakan 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, B

Mengesahkan 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:

#sertakan

menggunakan 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, A

6, 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:

#sertakan

menggunakan 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, 0

Apabila 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:

#sertakan

menggunakan 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, 0

Sekiranya 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, 0

Perhatikan 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:

#sertakan

menggunakan 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, 1

Catatan : = 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:

#sertakan

menggunakan 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, 0

Perhatikan 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:

#sertakan

menggunakan 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 pokok

Sekarang

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:

#sertakan

menggunakan 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:

#sertakan

menggunakan 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.