5 -ma'ruza. Qiymatlar fazosida λ-kesishuv nazariyasi. Λl – to’plamni qurish algoritmlari. Reja


O'zgaruvchilarni tashqi kontekstdan olish



Download 51,99 Kb.
bet6/8
Sana28.06.2022
Hajmi51,99 Kb.
#714026
1   2   3   4   5   6   7   8
Bog'liq
Лекция 5uzb

5. O'zgaruvchilarni tashqi kontekstdan olish.
Yuqoridagi barcha lambda ifodalar anonim funksiyalarga o'xshaydi, chunki ular hech qanday oraliq holatni saqlamagan. Lekin C++ tilidagi lambda ifodalar anonim funktorlar hisoblanadi, ya'ni ular lambda ifodalaridan foydalanib, foydalanuvchi belgilagan oraliqdagi [low; upper) holatni saqlashi mumkin!:
//6-kod
#include
#include
#include
#include
#include
#include
using namespace std;
int main() {
vector srcVec;
for (int val = 0; val < 10; val++) {
srcVec.push_back(val);
}
int lowerBound = 0, upperBound = 0;
cout << "Enter the value range: ";
cin >> lowerBound >> upperBound;
int result = count_if(srcVec.begin(), srcVec.end(),
[lowerBound, upperBound] (int _n) {
return lowerBound <= _n && _n < upperBound;
});
cout << result << endl;
return EXIT_SUCCESS;
}
Nihoyat, lambda ifodasi bo'sh qavslar bilan boshlanmaydigan nuqtaga keldik. 6-kodda ko'rinib turibdiki, o'zgaruvchilar kvadrat qavslar ichiga joylashtirilishi mumkin. Bu "qo'lga olish ro'yxati" (capture list) deb ataladi. Bu nima uchun? Bir qarashda, lambda ifodasining tashqi ta’sir doirasi main() funksiyasi bo'lib tuyulishi mumkin va unda e'lon qilingan o'zgaruvchilardan lambda ifodasi tanasi ichida erkin foydalanish mumkin bo’ladi, ammo bu unday emas. Nega? Chunki aslida lambda tanasi anonim funktor ichidagi haddan tashqari yuklangan operator()() tanasidir, yaʼni 6-koddagi uchun, kompilyator bilvosita shunga o'xshash narsani yaratadi:
// 7-kod
#include
#include
#include
#include
#include
using namespace std;
class MyLambda {
public:
MyLambda(int _lowerBound, int _upperBound)
: m_lowerBound(_lowerBound), m_upperBound(_upperBound) {}
bool operator ()(int _n) const {
return m_lowerBound <= _n && _n < m_upperBound;
}
private:
int m_lowerBound, m_upperBound;
};
int main() {
vector srcVec;
for (int val = 0; val < 10; val++) {
srcVec.push_back(val);
}
int lowerBound = 0, upperBound = 0;
cout << "Enter the value range: ";
cin >> lowerBound >> upperBound;
int result = count_if(srcVec.begin(),
srcVec.end(),
MyLambda(lowerBound, upperBound));
cout << result << endl;
return EXIT_SUCCESS;
}
7-kod yuqoridagi holatlarni biroz kengroq tushinishga yordam beradi. lambda funktorga aylandi, uning ichida main()da e'lon qilingan o'zgaruvchilardan to'g'ridan-to'g'ri foydalana olmaydi, chunki ular bir-biriga mos kelmaydigan sohalar hisoblanadi. lowerBound va upperBound-ga kirish imkoniga ega bo'lish uchun bu o'zgaruvchilar funktorning o'zida saqlanadi (xuddi shunday "qo'lga olish" sodir bo'ladi): konstruktor ularni ishga tushiradi va operator()() ichida ishlatiladi. Farqni ko’rsatish uchun ataylab bu o'zgaruvchilarga "m_" prefiksi bilan boshlanadigan nomlar berilgan.
Agar biz lambda ichidagi "qo'lga olingan" o'zgaruvchilarni o'zgartirishga harakat qilsak, biz muvaffaqiyatsiz bo'lamiz, chunki sukut bo'yicha yaratilgan operator()() const deb e'lon qilinadi. Buni hal qilish uchun biz quyidagi misolda bo'lgani kabi o'zgaruvchan spetsifikatsiyani belgilashimiz mumkin:
//8-kod
#include
#include
#include
#include
#include
#include
using namespace std;
int main() {
vector srcVec;
int init = 0;
generate_n(back_inserter(srcVec), 10, [init] () mutable {
return init++;
});
ostream_iterator outIt(cout, " ");
copy(srcVec.begin(), srcVec.end(), outIt);
cout << endl << "init: " << init << endl;
return EXIT_SUCCESS;
}

Yuqorida aytib o'tgan edimki, lambda parametrlari ro'yxati bo'sh bo'lganda o'tkazib yuborilishi mumkin, ammo kompilyator o'zgaruvchan so'zdan foydalanishni to'g'ri tahlil qilishi uchun biz bo'sh parametrlar ro'yxatini aniq ko'rsatishimiz kerak.


8-kod dasturini ishga tushirganimizda, biz quyidagilarni olamiz:
0 1 2 3 4 5 6 7 8 9
init: 0
Ko'rib turganingizdek, mutable kalit so'z tufayli biz lambda ifodasi tanasi ichidagi "qo'lga olingan" o'zgaruvchining qiymatini o'zgartirishimiz mumkin, ammo siz kutganingizdek, bu o'zgarishlar mahalliy o'zgaruvchida aks etmaydi, chunki qiymati bo'yicha qo'lga olish sodir bo'ladi. C++ bizga mos yozuvlar bo'yicha o'zgaruvchilarni qo'lga kiritish va hatto standart "qo'lga olish rejimini" belgilash imkonini beradi. Standart "qo'lga olingan" rejimini belgilash uchun maxsus sintaksis mavjud: mos ravishda qiymat [=] yoki mos yozuvlar bo'yicha "qo'lga olingan" uchun [&]. Bunday holda, har bir o'zgaruvchi uchun siz o'zingizning "qo'lga olingan" rejimingizni belgilashingiz mumkin, ammo standart rejim, albatta, faqat bir marta va "qo'lga olingan" ro'yxatining boshida ko'rsatiladi. Bu yerda foydalanish holatlari:
[] // o'zgaruvchilarni tashqi doiradan tortib olmasdan
[=] // barcha o'zgaruvchilar qiymat bo'yicha olinadi
[&] // barcha o'zgaruvchilar mos yozuvlar orqali olinadi
[x, y] // qiymat bo'yicha x va y ni olish
[&x, &y] // mos yozuvlar bo'yicha x va y ni olish
[in, &out] // qiymat bo'yicha kirish va mos yozuvlar bo'yicha chiqish
[=, &out1, &out2] // out1 va out2dan tashqari barcha oʻzgaruvchilarni qiymat boʻyicha yozib olish
[&, x, &y] // x dan tashqari barcha o'zgaruvchilarni mos yozuvlar bo'yicha yozib olish...
E'tibor bering, bu holda &out kabi sintaksis manzilni olishni anglatmaydi. U ko'proq SomeType & out kabi o'qilishi kerak, ya'ni u faqat mos yozuvlar bo'yicha parametrdan o'tadi.
Misol:
// 9-kod
#include
#include
#include
#include
#include
using namespace std;
int main() {
vector srcVec;
int init = 0;
generate_n(back_inserter(srcVec), 10, [&] () mutable {
return init++;
});
ostream_iterator outIt(cout, " ");
copy(srcVec.begin(), srcVec.end(), outIt);
cout << endl << "init: " << init << endl;
return EXIT_SUCCESS;
}
Bu safar, init o'zgaruvchisini aniq qo'lga kiritish o'rniga, standart rejim ko'rsatildi: [&]. Endi, kompilyator lambda tanasi ichidagi tashqi kontekstdan o'zgaruvchiga duch kelganida, u avtomatik ravishda havola orqali uni yozib oladi. Mana 9-kodga ekvivalent kod:
//10-kod
#include
#include
#include
#include
#include
using namespace std;
class MyLambda {
public:
explicit MyLambda(int & _init) : init(_init) { }
int operator ()() { return init++; }
private:
int & init;
};
int main() {
vector srcVec;
int init = 0;
generate_n(back_inserter(srcVec), 10, MyLambda(init));
ostream_iterator outIt(cout, " ");
copy(srcVec.begin(), srcVec.end(), outIt);
cout << endl << "init: " << init << endl;
return EXIT_SUCCESS;
}
Va shunga ko'ra, chiqish quyidagicha bo'ladi:
0 1 2 3 4 5 6 7 8 9
init: 10
Endi siz uchun asosiy narsa ma'lumotnoma bo'yicha nimani, qayerda va qachon o'tish haqida chalkashmaslikdir. Haqiqatan ham, agar [&] ni belgilab, o'zgaruvchanligini belgilamasak, biz hali ham olingan o'zgaruvchining qiymatini o'zgartirishimiz mumkin va bu mahalliy qiymatda aks etadi, chunki operator()() const havolani o'zgartira olmasligimizni bildiradi.
Agar lambda ifodasi [=] (int & _val) mutable { … }, ga oʻxshasa, u holda oʻzgaruvchilar qiymat boʻyicha olinadi, lekin faqat ularning ichki nusxasi oʻzgaradi, lekin parametr mos yozuvlar boʻyicha uzatiladi, yaʼni oʻzgarishlar shunday boʻladi. Agar [] (const SomeBigObject & _val) { … } boʻlsa, unda hech narsa olinmaydi va parametr doimiy havola orqali olinadi va hokazo.
//11-kod
#include
#include
#include
#include
#include
using namespace std;
class MyMegaInitializer {
public:
MyMegaInitializer(int _base, int _power)
: m_val(_base), m_power(_power) {}
void initializeVector(vector & _vec) {
for_each(_vec.begin(), _vec.end(),
[m_val, m_power] (int & _val) mutable {
_val = m_val;
m_val *= m_power;
});
}
private:
int m_val, m_power;
};
int main() {
vector myVec(11);
MyMegaInitializer initializer(1, 2);
initializer.initializeVector(myVec);
return EXIT_SUCCESS;
}
Bizning barcha taxminlarimizga qaramay, kod kompilyatsiya qilinmaydi, chunki kompilyator m_val va m_power ni qo'lga kirita olmaydi: bu o'zgaruvchilar doiradan tashqarida. Visual Studioda quyidagicha xatolik beradi:
«error C3480: 'MyMegaInitializer::m_power': a lambda capture variable must be from an enclosing function scope»
Qanday bo'lish kerak? Sinf a'zolariga kirish uchun siz buni qamrab olish ro'yxatiga kiritishingiz kerak:
//12-kod
#include
#include
#include
#include
#include
using namespace std;
class MyMegaInitializer {
public:
MyMegaInitializer(int _base, int _power)
: m_val(_base), m_power(_power) {}
void initializeVector(vector & _vec) {
for_each(_vec.begin(), _vec.end(), [this] (int & _val) mutable {
_val = m_val;
m_val *= m_power;
});
}
private:
int m_val, m_power;
};
int main() {
vector myVec(11);
MyMegaInitializer initializer(1, 2);
initializer.initializeVector(myVec);
for_each(myVec.begin(), myVec.end(), [] (int _val) {
cout << _val << " ";
});
cout << endl;
return EXIT_SUCCESS;
}
Ushbu dastur biz kutgan narsani bajaradi:
1 2 4 8 16 32 64 128 256 512 1024
Shuni yodda tutingki, buni faqat qiymat bo'yicha olish mumkin va agar siz mos yozuvlar bo'yicha olishga harakat qilsangiz, kompilyator xatoga yo'l qo'yadi. 12-kodda [this] o‘rniga [&] yozsangiz ham, this qiymat bo‘yicha yozib olinadi.



Download 51,99 Kb.

Do'stlaringiz bilan baham:
1   2   3   4   5   6   7   8




Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©hozir.org 2024
ma'muriyatiga murojaat qiling

kiriting | ro'yxatdan o'tish
    Bosh sahifa
юртда тантана
Боғда битган
Бугун юртда
Эшитганлар жилманглар
Эшитмадим деманглар
битган бодомлар
Yangiariq tumani
qitish marakazi
Raqamli texnologiyalar
ilishida muhokamadan
tasdiqqa tavsiya
tavsiya etilgan
iqtisodiyot kafedrasi
steiermarkischen landesregierung
asarlaringizni yuboring
o'zingizning asarlaringizni
Iltimos faqat
faqat o'zingizning
steierm rkischen
landesregierung fachabteilung
rkischen landesregierung
hamshira loyihasi
loyihasi mavsum
faolyatining oqibatlari
asosiy adabiyotlar
fakulteti ahborot
ahborot havfsizligi
havfsizligi kafedrasi
fanidan bo’yicha
fakulteti iqtisodiyot
boshqaruv fakulteti
chiqarishda boshqaruv
ishlab chiqarishda
iqtisodiyot fakultet
multiservis tarmoqlari
fanidan asosiy
Uzbek fanidan
mavzulari potok
asosidagi multiservis
'aliyyil a'ziym
billahil 'aliyyil
illaa billahil
quvvata illaa
falah' deganida
Kompyuter savodxonligi
bo’yicha mustaqil
'alal falah'
Hayya 'alal
'alas soloh
Hayya 'alas
mavsum boyicha


yuklab olish