C++'da Lambda İfadeleri

Lambda Expressions C



Neden Lambda İfadesi?

Aşağıdaki ifadeyi göz önünde bulundurun:

intbenimInt= 52;

Burada myInt bir tanımlayıcı, bir değerdir. 52 bir değişmez, bir değerdir. Günümüzde bir fonksiyonu özel olarak kodlayıp 52 konumuna getirmek mümkündür. Böyle bir fonksiyona lambda ifadesi denir. Aşağıdaki kısa programı da göz önünde bulundurun:







#Dahil etmek

kullanarak ad alanısaat;

intfn(intvasıtasıyla)

{

intCevap=vasıtasıyla+ 3;

dönüşCevap;

}


intana()

{

fn(5);



dönüş 0;

}

Bugün, bir işlevi özel olarak kodlamak ve onu fn(5) işlev çağrısının 5 argümanının yerine koymak mümkündür. Böyle bir fonksiyona lambda ifadesi denir. Bu konumdaki lambda ifadesi (işlev) bir değerdir.



Dize değişmezi dışındaki herhangi bir değişmez değer bir ön değerdir. Lambda ifadesi, kodda değişmez olarak sığacak özel bir işlev tasarımıdır. Anonim (adsız) bir işlevdir. Bu makale, lambda ifadesi olarak adlandırılan yeni C++ birincil ifadesini açıklamaktadır. Bu makaleyi anlamak için temel C++ bilgisi gereklidir.



Makale İçeriği

Lambda ifadesinin çizimi

Aşağıdaki programda, bir değişkene lambda ifadesi olan bir fonksiyon atanmıştır:





#Dahil etmek

kullanarak ad alanısaat;

Otofn= [](intDur)

{

intCevap=Dur+ 3;

dönüşCevap;

};


intana()

{

Otodeğişken=fn(2);

maliyet <<değişken<< ' ';


dönüş 0;

}

Çıktı:

5

main() işlevinin dışında, fn değişkeni vardır. Türü otomatiktir. Bu durumda otomatik, int veya float gibi gerçek türün, atama operatörünün (=) sağ işleneni tarafından belirlendiği anlamına gelir. Atama operatörünün sağ tarafında bir lambda ifadesi bulunur. Bir lambda ifadesi, önceki dönüş türü olmayan bir işlevdir. Köşeli parantezlerin [] kullanımına ve konumuna dikkat edin. İşlev, fn'nin türünü belirleyecek olan bir int olan 5'i döndürür.



main() işlevinde şu ifade vardır:

Otodeğişken=fn(2);

Bu, main() dışında fn'nin bir işlevin tanımlayıcısı olarak sona erdiği anlamına gelir. Örtük parametreleri lambda ifadesinin parametreleridir. Değişkenin türü auto'dur.

Lambda ifadesinin, sınıf veya yapı tanımı gibi noktalı virgülle bittiğine dikkat edin, noktalı virgülle biter.

Aşağıdaki programda, 5 değerini döndüren bir lambda ifadesi olan bir fonksiyon, başka bir fonksiyonun argümanıdır:

#Dahil etmek

kullanarak ad alanısaat;

geçersizdiğer fn(int1 numaraint (*ptr)(int))

{

intno2= (*ptr)(2);

maliyet <<1 numara<< '' <<no2<< ' ';

}


intana()

{

diğer fn(4,[](intDur)

{

intCevap=Dur+ 3;

dönüşCevap;

});


dönüş 0;
}

Çıktı:

Dört beş

Burada lambda ifadesi ve otherfn() işlevi olmak üzere iki işlev vardır. Lambda ifadesi, ana() içinde çağrılan otherfn() öğesinin ikinci argümanıdır. Lambda işlevinin (ifadesinin) bu çağrıda noktalı virgülle bitmediğini unutmayın, çünkü burada bir argümandır (tek başına bir işlev değil).

otherfn() işlevinin tanımındaki lambda işlevi parametresi, bir işlevin işaretçisidir. İşaretçinin adı ptr. ptr adı, otherfn() tanımında lambda işlevini çağırmak için kullanılır.

İfade,

intno2= (*ptr)(2);

otherfn() tanımında, 2 argümanıyla lambda işlevini çağırır. Lambda işlevinden gelen '(*ptr)(2)' çağrısının dönüş değeri no2'ye atanır.

Yukarıdaki program ayrıca lambda işlevinin C++ geri çağırma işlevi şemasında nasıl kullanılabileceğini gösterir.

Lambda İfadesinin Parçaları

Tipik bir lambda fonksiyonunun bölümleri aşağıdaki gibidir:

[] () {}
  • [] yakalama yan tümcesidir. Eşyalara sahip olabilir.
  • () parametre listesi içindir.
  • {} işlev gövdesi içindir. İşlev tek başına duruyorsa, noktalı virgülle bitmelidir.

Yakalar

Lambda fonksiyon tanımı bir değişkene atanabilir veya farklı bir fonksiyon çağrısına argüman olarak kullanılabilir. Böyle bir işlev çağrısının tanımı, bir parametre olarak, lambda işlevi tanımına karşılık gelen bir işleve yönelik bir işaretçiye sahip olmalıdır.

Lambda işlev tanımı, normal işlev tanımından farklıdır. Global kapsamda bir değişkene atanabilir; değişkene atanan bu işlev, başka bir işlevin içinde de kodlanabilir. Bir global kapsam değişkenine atandığında, gövdesi global kapsamdaki diğer değişkenleri görebilir. Normal bir fonksiyon tanımı içinde bir değişkene atandığında, onun gövdesi fonksiyon kapsamındaki diğer değişkenleri sadece yakalama yan tümcesinin yardımı ile görebilir, [].

Lambda tanıtıcısı olarak da bilinen yakalama yan tümcesi [], değişkenlerin çevreleyen (işlev) kapsamından lambda ifadesinin işlev gövdesine gönderilmesine izin verir. Lambda ifadesinin işlev gövdesinin, nesneyi aldığında değişkeni yakaladığı söylenir. Capture yan tümcesi [] olmadan, çevreleyen kapsamdan lambda ifadesinin işlev gövdesine bir değişken gönderilemez. Aşağıdaki program, bunu çevreleyen kapsam olarak main() işlev kapsamıyla birlikte gösterir:

#Dahil etmek

kullanarak ad alanısaat;

intana()

{

intİD= 5;


Otofn= [İD]()

{

maliyet <<İD<< ' ';

};

fn();


dönüş 0;

}

çıktı 5 . [] içindeki id adı olmasaydı, lambda ifadesi main() işlev kapsamının id değişkenini görmezdi.

Referansa Göre Yakalama

Capture yan tümcesinin yukarıdaki örnek kullanımı, değere göre yakalamadır (aşağıdaki ayrıntılara bakın). Referansla yakalamada, çevreleyen kapsamın örneğin yukarıdaki id gibi değişkenin konumu (depolama) lambda işlevi gövdesi içinde kullanıma sunulur. Bu nedenle, lambda işlevi gövdesi içindeki değişkenin değerini değiştirmek, aynı değişkenin çevresindeki kapsamdaki değerini değiştirecektir. Bunu başarmak için yakalama yan tümcesinde tekrarlanan her değişkenden önce ve işareti (&) gelir. Aşağıdaki program bunu göstermektedir:

#Dahil etmek

kullanarak ad alanısaat;

intana()

{

intİD= 5; batmadan yüzmekft= 2.3; karakterch= 'İLE';

Otofn= [&İD,&ft,&ch]()

{

İD= 6;ft= 3.4;ch= 'B';

};

fn();

maliyet <<İD<< ',' <<ft<< ',' <<ch<< ' ';

dönüş 0;

}

Çıktı:

6, 3.4, B

Lambda ifadesinin işlev gövdesi içindeki değişken adlarının lambda ifadesinin dışındaki aynı değişkenler için olduğunu doğrulama.

Değere Göre Yakalama

Değere göre yakalamada, değişkenin konumunun, çevreleyen kapsamın bir kopyası lambda işlevi gövdesi içinde kullanıma sunulur. Lambda işlevi gövdesi içindeki değişken bir kopya olsa da, değeri şu anda gövde içinde değiştirilemez. Değere göre yakalamayı başarmak için, yakalama yan tümcesinde tekrarlanan her değişkenden önce hiçbir şey gelmez. Aşağıdaki program bunu göstermektedir:

#Dahil etmek

kullanarak ad alanısaat;

intana()

{

intİD= 5; batmadan yüzmekft= 2.3; karakterch= 'İLE';

Otofn= [kimlik, ft, ch]()

{

//id = 6; ft = 3.4; ch = 'B';

maliyet <<İD<< ',' <<ft<< ',' <<ch<< ' ';

};

fn();

İD= 6;ft= 3.4;ch= 'B';

maliyet <<İD<< ',' <<ft<< ',' <<ch<< ' ';

dönüş 0;

}

Çıktı:

5, 2.3, Bir

6, 3.4, B

Yorum göstergesi kaldırılırsa program derlenmeyecektir. Derleyici, fonksiyon gövdesinin lambda ifadesinin tanımındaki değişkenlerin değiştirilemeyeceğine dair bir hata mesajı verecektir. Değişkenler lambda fonksiyonunun içinde değiştirilemese de, yukarıdaki programın çıktısının gösterdiği gibi, lambda fonksiyonunun dışında değiştirilebilirler.

Yakalamaları Karıştırma

Aşağıdaki programda gösterildiği gibi, referansa göre yakalama ve değere göre yakalama karıştırılabilir:

#Dahil etmek

kullanarak ad alanısaat;

intana()

{

intİD= 5; batmadan yüzmekft= 2.3; karakterch= 'İLE'; boolbl= NS;


Otofn= [kimlik, ft,&ch,&bl]()

{

ch= 'B';bl= YANLIŞ;

maliyet <<İD<< ',' <<ft<< ',' <<ch<< ',' <<bl<< ' ';

};

fn();


dönüş 0;

}

Çıktı:

5, 2.3, B, 0

Hepsi yakalandığında, referans olarak:

Yakalanacak tüm değişkenler referans tarafından yakalanırsa, yakalama yan tümcesinde yalnızca bir & yeterli olacaktır. Aşağıdaki program bunu göstermektedir:

#Dahil etmek

kullanarak ad alanısaat;

intana()

{

intİD= 5; batmadan yüzmekft= 2.3; karakterch= 'İLE'; boolbl= NS;


Otofn= [&]()

{

İD= 6;ft= 3.4;ch= 'B';bl= YANLIŞ;

};

fn();

maliyet <<İD<< ',' <<ft<< ',' <<ch<< ',' <<bl<< ' ';


dönüş 0;

}

Çıktı:

6, 3.4, B, 0

Bazı değişkenler referansla ve diğerleri değerle yakalanacaksa, bir & tüm referansları temsil edecek ve aşağıdaki programın gösterdiği gibi geri kalanların her birinin önünde hiçbir şey olmayacak:

kullanarak ad alanısaat;

intana()

{

intİD= 5; batmadan yüzmekft= 2.3; karakterch= 'İLE'; boolbl= NS;


Otofn= [&, kimlik, ft]()

{

ch= 'B';bl= YANLIŞ;

maliyet <<İD<< ',' <<ft<< ',' <<ch<< ',' <<bl<< ' ';

};

fn();


dönüş 0;

}

Çıktı:

5, 2.3, B, 0

& tek başına (yani & arkasından bir tanımlayıcı gelmeden) yakalama yan tümcesindeki ilk karakter olması gerektiğini unutmayın.

Hepsi yakalandığında, değere göredir:

Yakalanacak tüm değişkenler değer tarafından yakalanacaksa, yakalama yan tümcesinde yalnızca bir = yeterli olacaktır. Aşağıdaki program bunu göstermektedir:

#Dahil etmek

kullanarak ad alanısaat;

intana()
{

intİD= 5; batmadan yüzmekft= 2.3; karakterch= 'İLE'; boolbl= NS;


Otofn= [=]()

{

maliyet <<İD<< ',' <<ft<< ',' <<ch<< ',' <<bl<< ' ';

};

fn();


dönüş 0;


}

Çıktı:

5, 2.3, A, 1

Not : = şu an itibariyle salt okunurdur.

Bazı değişkenler değere ve diğerleri referansa göre yakalanacaksa, aşağıdaki programın gösterdiği gibi, bir = tüm salt okunur kopyalanan değişkenleri temsil edecek ve geri kalanların her birinde & olacaktır:

#Dahil etmek

kullanarak ad alanısaat;

intana()

{

intİD= 5; batmadan yüzmekft= 2.3; karakterch= 'İLE'; boolbl= NS;


Otofn= [=,&ch,&bl]()

{

ch= 'B';bl= YANLIŞ;

maliyet <<İD<< ',' <<ft<< ',' <<ch<< ',' <<bl<< ' ';

};

fn();


dönüş 0;

}

Çıktı:

5, 2.3, B, 0

= öğesinin, yakalama yan tümcesindeki ilk karakter olması gerektiğini unutmayın.

Lambda İfadeli Klasik Geri Çağırma İşlev Şeması

Aşağıdaki program, lambda ifadesi ile klasik bir geri çağırma işlevi şemasının nasıl yapılabileceğini gösterir:

#Dahil etmek

kullanarak ad alanısaat;

karakter *çıktı;


Otocba= [](karakterdışarı[])

{

çıktı=dışarı;

};



geçersizmainFunc(karaktergiriş[],geçersiz (*için)(karakter[]))

{

(*için)(giriş);

maliyet<<'ana işlev için'<<' ';

}


geçersizfn()

{

maliyet<<'Şimdi'<<' ';

}


intana()

{

karaktergiriş[] = 'geri arama işlevi için';

mainFunc(girdi, cba);

fn();

maliyet<<çıktı<<' ';



dönüş 0;

}

Çıktı:

ana işlev için

Şimdi

geri arama işlevi için

Global kapsamdaki bir değişkene bir lambda ifadesi tanımı atandığında, fonksiyon gövdesinin yakalama yan tümcesini kullanmadan global değişkenleri görebileceğini hatırlayın.

Sondaki dönüş tipi

Bir lambda ifadesinin dönüş tipi auto'dur, yani derleyici dönüş tipini dönüş ifadesinden (varsa) belirler. Programcı gerçekten dönüş tipini belirtmek isterse, bunu aşağıdaki programdaki gibi yapacaktır:

#Dahil etmek

kullanarak ad alanısaat;

Otofn= [](intDur) -> int

{

intCevap=Dur+ 3;

dönüşCevap;

};


intana()

{

Otodeğişken=fn(2);

maliyet <<değişken<< ' ';


dönüş 0;

}

Çıktı 5'tir. Parametre listesinden sonra ok operatörü yazılır. Bunu, dönüş türü (bu durumda int) takip eder.

kapatma

Aşağıdaki kod segmentini göz önünde bulundurun:

yapıKla

{

intİD= 5;

karakterch= 'ile';

}obj1, obj2;

Burada Cla, yapı sınıfının adıdır. Obj1 ve obj2, struct sınıfından örneklenecek iki nesnedir. Lambda ifadesi uygulamada benzerdir. Lambda işlev tanımı bir tür sınıftır. Lambda işlevi çağrıldığında (çağrıldığında), tanımından bir nesne başlatılır. Bu nesneye kapatma denir. Lambda'nın yapması beklenen işi yapan kapanıştır.

Ancak, yukarıdaki yapı gibi lambda ifadesini kodlamak, obj1 ve obj2'nin karşılık gelen parametrelerin argümanları ile değiştirilmesini sağlayacaktır. Aşağıdaki program bunu göstermektedir:

#Dahil etmek

kullanarak ad alanısaat;

Otofn= [](intparam1,intparam2)

{

intCevap=param1+param2;

dönüşCevap;

} (2,3);


intana()

{

Otonerede=fn;

maliyet <<nerede<< ' ';


dönüş 0;

}

Çıktı 5'tir. Argümanlar parantez içinde 2 ve 3'tür. Argümanlar lambda işlevi tanımının sonunda zaten kodlanmış olduğundan, fn lambda ifade işlev çağrısının herhangi bir argüman almadığına dikkat edin.

Çözüm

Lambda ifadesi anonim bir işlevdir. İki bölümden oluşur: sınıf ve nesne. Tanımı bir tür sınıftır. İfade çağrıldığında, tanımdan bir nesne oluşturulur. Bu nesneye kapatma denir. Lambda'nın yapması beklenen işi yapan kapanıştır.

Lambda ifadesinin bir dış işlev kapsamından bir değişken alması için, işlev gövdesine boş olmayan bir yakalama yan tümcesi gerekir.