C++ Lambda ifodalari
C++ Lambda ifodasi bizga inline sifatida ishlatilishi yoki argument sifatida uzatilishi mumkin bo'lgan anonim funksiya ob'ektlarini ( functors ) aniqlash imkonini beradi.
Lambda ifodasi C++ 11 da anonim funktorlarni yanada qulayroq va ixcham tarzda yaratish uchun kiritilgan.
Ular qulayroq, chunki biz alohida sinf yoki tuzilmada () operatorini ortiqcha yuklashimiz shart emas.
Asosiy lambda ifodasi quyidagicha ko'rinishi mumkin:
auto greet = []() {
// lambda funksiyasi tanasi
};
Bu yerga,
-[] lambda ifodasining boshlanishini bildiruvchi lambda kirituvchisi deb ataladi
-() oddiy funksiyaning () operatoriga o'xshash parametrlar ro'yxati deb ataladi
Yuqoridagi kod quyidagiga teng:
void greet() {
// funksiya tanasi
}
Endi, xuddi oddiy funksiyalar singari, biz lambda ifodasini oddiygina ishlatishimiz mumkin:
greet();
[!NOTE] Biz lambda ifodasi uchun qaytish turini avtomatik ravishda chiqarish uchun
autokalit so'zidan foydalandik.
#include <iostream>
using namespace std;
int main() {
// "Salom Dunyo!"ni chop etadigan lambda funksiyasini yarating.
auto greet = []() {
cout << "Hello World!";
};
// lambda funksiyasini chaqiring
greet();
return 0;
}
Chiqish
Hello World!
Yuqoridagi misolda biz C++ lambda ifodasi yordamida Hello World! ni chop etadigan oddiy dastur yaratdik.
Birinchidan, biz lambda funksiyasini yaratdik va uni greet nomli o'zgaruvchiga tayinladik.
auto greet = []() {
cout << "Hello World!";
};
Keyin, biz () operatori bilan birga salomlash o'zgaruvchisi yordamida lambda funksiyasini chaqirdik:
// "Salom dunyo!"
greet();
Oddiy funksiya singari, lambda ifodalari ham parametrlarni qabul qilishi mumkin. Masalan,
#include <iostream>
using namespace std;
int main() {
// ikki butun sonni qabul qiluvchi lambda funksiyasi
// parametrlarini ko'rsatadi va ularning yig'indisini ko'rsatadi
auto add = [] (int a, int b) {
cout << "Sum = " << a + b;
};
// lambda funksiyasini chaqiring
add(100, 78);
return 0;
}
Chiqish
Sum = 178
Yuqoridagi misolda biz ikkita tamsayı parametrini oladigan va ularning yig'indisini ko'rsatadigan lambda funksiyasini yaratdik.
auto add = [] (int a, int b) {
cout << "Sum = " << a + b;
};
Bu quyidagilarga teng:
void add(int a, int b) {
cout << "Sum = " << a + b;
}
Keyin biz ikkita tamsayı argumentini o'tkazish orqali lambda funksiyasini chaqirdik:
// 178 ni qaytaradi
add(100, 78);
Oddiy funksiyalarda bo'lgani kabi, C++ lambda ifodalari ham qaytish turiga ega bo'lishi mumkin.
Kompilyator return operator(lar)i asosida lambda ifodasining qaytish turini bilvosita chiqarishi mumkin.
auto add = [] (int a, int b) {
// har doim "int" ni qaytaradi
return a + b;
};
Yuqoridagi holatda biz lambda funksiyasi uchun qaytarish turini aniq belgilab bermadik. Buning sababi, har doim butun sonni qaytaradigan bitta return operatori mavjud.
Ammo har xil turdagi bir nechta return operatorlari uchun biz turni aniq belgilashimiz kerak. Masalan,
auto operation = [] (int a, int b, string op) -> double {
if (op == "sum") {
// butun son qiymatini qaytaradi
return a + b;
}
else {
// ikki barobar qiymatni qaytaradi
return (a + b) / 2.0;
}
};
Yuqoridagi -> double kodiga e'tibor bering. Bu qaytarish turini double sifatida aniq belgilaydi, chunki op qiymatiga qarab har xil turlarni qaytaradigan bir nechta iboralar mavjud.
Shunday qilib, har xil return iboralari tomonidan qaysi turdagi qiymat qaytarilmasin, ularning barchasi aniq double turiga aylantiriladi.
#include<iostream>
using namespace std;
int main() {
// lambda funksiyasi aniq qaytish turi "double"
// operatsiyaga qarab summani yoki o'rtachani qaytaradi
auto operation = [] (int a, int b, string op) -> double {
if (op == "sum") {
return a + b;
}
else {
return (a + b) / 2.0;
}
};
int num1 = 1;
int num2 = 2;
// 1 va 2 sonlarining yig'indisini toping
auto sum = operation(num1, num2, "sum");
cout << "Sum = " << sum << endl;
// 1 va 2 sonining o'rtachasini toping
auto avg = operation(num1, num2, "avg");
cout << "Average = " << avg;
return 0;
}
Chiqish
Sum = 3
Average = 1.5
Yuqoridagi misolda biz ikkitasini topish uchun lambda funksiyasini yaratdik:
auto operation = [] (int a, int b, string op) -> double {
if (op == "sum") {
// "int" qaytaradi
return a + b;
}
else {
// "juft" ni qaytaradi
return (a + b) / 2.0;
}
};
main() da biz birinchi navbatda "sum" ni uchinchi argument sifatida uzatish orqali 1 va 2 sonlarning yig'indisini topamiz:
auto sum = operation(num1, num2, "sum");
Bu erda, lambda butun son qiymatini qaytarsa ham, u aniq double turiga aylantiriladi.
Keyin, biz argument sifatida boshqa qatorni o'tkazish orqali o'rtachani topamiz:
auto avg = operation(num1, num2, "avg");
Odatiy bo'lib, lambda funksiyalari qo'shuvchi funksiyaning o'zgaruvchilariga kira olmaydi. Ushbu o'zgaruvchilarga kirish uchun biz capture bandidan foydalanamiz.
O'zgaruvchilarni ikki yo'l bilan olishimiz mumkin:
Bu calling a function by value ga o'xshaydi. Bu erda lambda yaratilganda haqiqiy qiymat ko'chiriladi.
[!NOTE] Bu erda biz faqat lambda tanasi ichidagi o'zgaruvchini o'qiy olamiz, lekin uni o'zgartira olmaymiz.
Qiymat bo'yicha qo'lga kiritilgan asosiy lambda ifodasi quyidagicha ko'rinadi:
int num_main = 100;
// qo'shuvchi funksiyadan num_main ga ruxsat oling
auto my_lambda = [num_main] () {
cout << num_main;
};
Bu erda [num_main] lambdaga num_main o'zgaruvchisiga kirish imkonini beradi.
Agar biz num_main ni tortib olish bandidan olib tashlasak, biz xatoga duch kelamiz, chunki num_main ga lambda tanasidan kirish mumkin emas.
Bu calling a function by reference ga o'xshaydi, ya'ni lambda o'zgaruvchan manzilga kirish huquqiga ega.
[!NOTE] Bu erda biz o'zgaruvchini o'qishimiz va uni lambda tanasi ichida o'zgartirishimiz mumkin.
Malumot orqali qo'lga olish bilan asosiy lambda ifodasi quyidagicha ko'rinadi:
int num_main = 100;
// num_main o'zgaruvchisining manziliga kirish
auto my_lambda = [&num_main] () {
num_main = 900;
};
[&num_main] da & operatoridan foydalanishga e'tibor bering. Bu biz num_main o'zgaruvchisining manzilini ushlayotganimizni ko'rsatadi.
#include<iostream>
using namespace std;
int main() {
int initial_sum = 100;
// boshlang'ich_sumni qiymat bo'yicha qo'lga kiriting
auto add_to_sum = [initial_sum] (int num) {
// bu yerda inital_sum = mahalliy miqyosdan 100
return initial_sum + num;
};
int final_sum = add_to_sum(78);
cout << "100 + 78 = " << final_sum;
return 0;
}
Chiqish
100 + 78 = 178
Yuqoridagi misolda biz initial_sum nomli mahalliy o'zgaruvchining yig'indisini va butun son parametrini qaytaruvchi lambda ifodasini yaratdik.
auto add_to_sum = [initial_sum] (int num) {
return initial_sum + num;
};
Bu erda [initial_sum] qo'shuvchi funksiyadan qiymat bo'yicha initial_sumni oladi.
Keyin, biz funksiyani chaqiramiz va uning qaytish qiymatini final_sum o'zgaruvchisida saqlaymiz.
int final_sum = add_to_sum(78);
Lambda funksiyasi ichida:
Natijada 100 + 78 bo'ladi, bu 178 ga teng.
[!NOTE] Aytaylik, biz bir nechta o'zgaruvchilarni qiymat bo'yicha olishni xohlaymiz. Misol uchun,
auto my_lambda = [a, b, c, d, e] (){ // lambda body }Ko'rib turganingizdek, bu juda zerikarli vazifa bo'lishi mumkin. Ishimizni osonlashtirish uchun biz shunchaki qiymat bo'yicha yashirin ushlashdan foydalanishimiz mumkin. Masalan,auto my_lambda = [=] (){ // lambda body }Bu yerda[=]qo'shuvchi funksiyaning barcha o'zgaruvchilari qiymat bo'yicha ushlanganligini aytadi.
#include <iostream>
using namespace std;
int main() {
int num = 0;
cout << "Initially, num = " << num << endl;
// [&num] ma'lumotnoma bo'yicha numni oladi
auto increment_by_one = [&num] () {
cout << "Incrementing num by 1.\n";
num++;
};
// lambda funksiyasini chaqirish
increment_by_one();
cout << "Now, num = " << num << endl;
return 0;
}
Chiqish
Initially, num = 0
Incrementing num by 1.
Now, num = 1
Yuqoridagi misolda biz num mahalliy o'zgaruvchining qiymatini 1 ga oshiradigan lambda funksiyasini yaratdik.
auto increment_by_one = [&num] () {
cout << "Incrementing num by 1.\n";
num++;
};
Bu erda [&num] mos yozuvlar bo'yicha raqamni olish uchun ishlatiladi.
Dastlab, sonning qiymati 0 ga teng.
Keyin, biz lambda ifodasini increment_by_one() deb ataymiz. Bu raqam qiymatini 1 ga oshiradi.
[!NOTE] Qo'shimcha funksiyaning barcha o'zgaruvchilarini qo'lga kiritish uchun biz shunchaki mos yozuvlar bo'yicha yashirin tutib olishdan foydalanishimiz mumkin. Masalan,
auto my_lambda = [&] (){ // lambda body }Bu erda[&]barcha o'zgaruvchilar mos yozuvlar orqali olinganligini bildiradi.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
// butun sonlar vektorini ishga tushirish
vector<int> nums = {1, 2, 3, 4, 5, 8, 10, 12};
int even_count = count_if(nums.begin(), nums.end(), [](int num) {
return num % 2 == 0;
});
cout << "There are " << even_count << " even numbers.";
return 0;
}
Chiqish
There are 5 even numbers.
Yuqoridagi misolda biz count_if algoritmida nums vektoridagi umumiy juft sonlarni hisoblash uchun lambda funksiyasidan foydalandik:
int even_count = count_if(nums.begin(), nums.end(), [](int num) {
return num % 2 == 0;
});
E'tibor bering, biz count_if ga uchinchi argument sifatida lambda ifodasini taqdim etdik. Lambda ifodasi butun sonni oladi va agar son juft bo'lsa, true ni qaytaradi.
Bundan tashqari, biz lambda ifodasini satrga o'tkazdik.
[](int num) {
return num % 2 == 0;
}
Tez-tez so'raladigan savollar Ha, biz bitta lambda ifodasida o'zgaruvchi bo'yicha capture va mos yozuvlar bo'yicha tortib olishdan foydalanishimiz mumkin. Misol uchun, [&num1, num2] - mos yozuvlar bo'yicha 1 raqamini va qiymat bo'yicha raqamni oling [&, num1, num2] - qiymat bo'yicha 1 va raqamlarni, qolganlarini esa mos yozuvlar bo'yicha [=, &num1, &num2] - 1 va 2 raqamini mos yozuvlar bo'yicha, qolganini esa qiymat bo'yicha qo'lga kiriting. Buni function<> shablonidan foydalanib qilishimiz mumkin. Buni amalga oshirish uchun biz birinchi navbatda <functional> sarlavha faylini import qilishimiz kerak. #include <iostream> #include<functional> using namespace std; int main() { function<void(int, int)> add = [] (int a, int b) { cout << "Sum: " << a + b; }; add(1, 2); return 0; } Chiqish summasi: 3 Bu yerda function<void(int, int)> lambda funksiyasi void turiga tegishli ekanligini va ikkita butun son parametrini qabul qilishini aniq aytadi. C++ 14 da lambda funksiyasida umumiy shablon parametrlarini qo‘llab-quvvatlash uchun umumiy lambda joriy qilingan. Masalan, #include <iostream> using namespace std; int main() { auto display = [] (auto s) { cout << s << endl; }; display(1); display(2.5); display("Kathmandu"); return 0; } Chiqish 1 2.5 Katmandu Yuqoridagi misolda biz umumiy turdagi parametrni qabul qilish va qiymatni chop etish uchun bitta lambda ifodasidan foydalanganmiz. auto display = [] (auto s){ cout << s << endl; }; Parametrlar ro'yxatida auto s kodiga e'tibor bering. Bu bizga har xil turdagi qiymatlarni lambda ifodasiga o'tkazish imkonini beradi. Lambda mutable kalit so'zi lambda-ga lambda tanasi ichidagi qiymat bo'yicha olingan o'zgaruvchini qo'shish funksiyasidagi asl qiymatiga ta'sir qilmasdan o'zgartirish imkonini beradi. Biroq, mos yozuvlar orqali olingan o'zgaruvchilar ta'sir qilmaydi. Masalan, #include <iostream> using namespace std; int main() { int a = 1; int b = 1; cout << "In main():" << endl; cout << "a = " << a << ", "; cout << "b = " << b << endl; cout << endl; auto add_one = [a, &b] () mutable { // modify both a & b a++; b++; cout << "In add_one():" << endl; cout << "a = " << a << ", "; cout << "b = " << b << endl; }; add_one(); cout << endl; cout << "In main():" << endl; cout << "a = " << a << ", "; cout << "b = " << b << endl; return 0; } Chiqishda main(): a = 1, b = 1 add_one(): a = 2, b = 2 main(): a = 1, b = 2 Yuqoridagi misolda sukut bo'yicha a o'zgaruvchisini o'zgartirib bo'lmaydi, chunki u qiymat bo'yicha ushlangan. Biroq, mutable kalit so'zi main() da asl qiymatini o'zgartirmasdan uni o'zgartirishga imkon beradi. auto add_one = [a, &b] () mutable { a++; b++; ... }; Buning sababi, lambda funksiyasi ichidagi o'zgaruvchining asl o'zgaruvchining alohida nusxasi. Shunday qilib, uni o'zgartirish main() da asl qiymatini o'zgartirmaydi. Darhol chaqirilgan lambda ifodasi lambda ifodasi bo'lib, u aniqlangandan so'ng darhol chaqiriladi. Misol uchun, #include<iostream> using namespace std; int main(){ int num1 = 1; int num2 = 2; // invoked as soon as it is defined auto sum = [] (int a, int b) { return a + b; } (num1, num2); cout << "The sum of " << num1 << " and " << num2 << " is " << sum; return 0; } Chiqish 1 va 2 ning yig'indisi 3 ga teng Yuqoridagi misolda biz ikkita butun sonning yig'indisini hisoblash uchun lambda ifodasini yaratdik, u darhol num1 va num2 argumentlari bilan chaqiriladi: auto sum = [] (int a, int b) { return a + b; } (num1, num2); C++ Lambda ifodasining kengaytirilgan sintaksisi: XCODE19 bilan taqqoslaganda ko'proq sintaksik ko'rishingiz mumkin. asosiy sintaksisni biz o'quv qo'llanmamizning boshida taqdim qildik. Buning sababi shundaki, u biz shu nuqtaga qadar muhokama qilgan barcha lambda elementlaridan iborat: [capture_list] - qamrab oluvchi funksiyaning o'zgaruvchilari (parameter_list) - mutable lambda ifodasi ichida ishlatiladigan parametrlar - qiymat bo'yicha olingan o'zgaruvchilarni lambda ichida o'zgartirishga imkon beradi XCODE23 ifodasi ifodasini aniqlaydi - XCODE23 ifodasini aniqlaydi.