Haftalık C++ 49 – “Generic Lambda” ve “Lambda Capture Initializers”

Merhaba yazılımperver dostlarım, C++ 14 yazılarımıza devam ediyoruz.
Bu yazımda kalan C++ 14 özelliklerinden olan Jenerik Lambda (“Generik Lambda”) ve “lambda capture initializers” kabiliyetlerine bakıyor olacağız. Bu iki kabiliyeti, daha önce C++ 11 ile sunulan Lambda kabiliyetleri üzerene yapılan iyileştirmeler olarak görebilirsiniz. Bu sebeple eğer daha önce incelemediyseniz aşağıdaki yazıma göz atmanızı şiddetle tavsiye ediyorum:

Modern C++ (6) : Lambda İfadeleri

Ayrıca mevcut C++ 14 kabiliyetleri yolculuğundaki durumumuz için de C++ 14 Kabiliyetler Yolcuğu yazısından takip edebilirsiniz. Haydi başlayalım.

Jenerik Lambda İfadeleri (“Generic Lambda”)

Bu kabiliyeti kısaca özetlemek için aslında C++ 11 de sunulan ve C++ 14 ile eklenen hususlara, jenerik lambda perspektifinde bakmakta fayda var. C++ 11 ile lambdaya geçirilen fonksiyon parametreleri sadece “pass-by-value” ve “pass-by-reference” mekanizmaları ile geçirilebilmekteydi. Bir diğer ifade ile, taşıma semantiği ile sunulan tipleri lambdalar ile direk kullanmanız mümkün olamıyordu ve auto da kullanılamamaktaydı.

Bu arada, bu mekanizmalara ve taşıma semantiğine ilişkin pek bir fikriniz yok ise, bu yazıya devam etmeden önce bunlara ilişkin bir fikir sahibi olmanızda fayda var. Bu bağlamda, aşağıdaki yazım sizlere, hem bu mekanizmalar hem de jenerik lambdalar ile sunulan kabiliyeti anlamanıza yardımcı olabilir:

Modern C++ (5) : Taşıma Semantikleri

C++ 14 ile birlikte artık lambda fonksiyon parametreleri için de auto ve taşıma semantiğine uygun tipler kullanabiliyoruz. Bununla birlikte, herhangi bir ifade ile ilklendirme de mümkün olabilmekte (bir sonraki başlıkta bakıyor olacağız). Hemen basit bir örneğe bakalım:

Burada gördüğünüz üzere, tek bir lambda ifadesini, farklı girdiler için kullanabiliyoruz ve derleyici sağolsun bizler için arka tarafta gerekli kodları üretiyor. Meraklı takipçilerimin bu kod parçasını hemen CompilerExplorer ile inceleyip, üzerinde oynayıp, arkada üretilen kodun nasıl değiştiğine baktığını umuyorum 🙂

Peki yukarıdaki kod parçasını derleyici nasıl değerlendiriyor ya da lambda’lar olmasaydı bunu nasıl elde ederdik? Aslında bakarsanız, temelde benzer davranışı aşağıdaki gibi bir kod parçası ile de elde edebiliriz:

Tabi, bunun yanında artık “perfect forwarding” de mümkün olabilmekte, daha doğrusu taşıma mekanizmasını da kullanabileceğiz ve artık aşağıdaki kullanımlara mümkün olabilecek:

Benzer şekilde, argümanların aktarılması ve “variadic” kullanım da mümkün:

Yukarıdaki örnek kullanımlar yanında, jenerik lambdalar ile özyinelemeli lambda tanımlamaları da daha temiz ve okunabilir şekilde tanımlanabilmekteymiş. Örneğin aşağıda, fibonacci hesaplamak için kullanılabilecek bir kod parçasını görebilirsiniz:

Bununla ne kadar işiniz olur bilemiyorum ama daha detaylı bilgi almak için https://artificial-mind.net/blog/2020/09/12/recursive-lambdas sayfasına göz atabilirsiniz.

Jenerik lambdaların son bir kullanımından daha bahsetmek istiyorum. O da, herhangi bir yakalama parametresi olmayan lambda ifadelerinin fonksiyon işsaretçilerine atanması olacak. Örneğin artık aşağıdaki ifade kullanılabilir olacak:

Sonuç olarak, bu kabiliyet ile ne elde ediliyor diye sorabiliriz? Şu elde ediliyor, modern C++ ile hedeflenen daha az kod satırı ile daha okunabilir ve idame edilebilir kodlar elde etmemize olanak sağlanıyor. Şu sayfadan bir örnek ile bu başlığı kapatalım:

C++11 ile yazılan aşağıdaki kodlar:

C++ 14 ile aşağıdaki hale dönüşebilmekteler:

ikincisi daha okunabilir değil mi?

Lambda Capture Initializer

Bir önceki başlıkta ifade ettiğim, lambda ifade argümanları yanında, lambda kullanımlarında artık herhangi bir ifade de yakalanabilecek ve yakalama ifadesinde kullanılan değişkenin daha önce tanımlanmasına ihtiyaç kalmayacak. Örneğin aşağıdaki ifade C++ 14 öncesinde uyarı ya da hata verecektir, çünkü bir üst kapsamda value tanımlı değil.

Jenerik lambdalar ile yukarıdaki kod parçası derlenebilir ve ilgili lambda ifadesi 1.5 döner ve bunun tipi de ilgili ifadeden çıkarılır. Aslında arkada yine auto kullanımını görüyoruz. Benzer şekilde taşıma mekanizması ile de yakalama yapılabilecek. Örneğin aşağıdaki kod içerisinde, nasıl taşıma yapıldığı görülebilir.

Ayrıca, yakalanan değişkenler, farklı isimlendirmelerle de kullanılabiliyor. Yine bir örnek ile bakalım:

Bu konulara ilave bilgilere erişmek isteyen takipçilerim için kaynaklar kısmına güzel bir iki site daha ekliyorum. Ayrıca, bu kabiliyetlere ilişkin standart öneri dokümanına da şu sayfadan ulaşabilirsiniz.

Bir sonraki yazımda görüşmek dileğiyle kendinize çok iyi bakın.

Kaynaklar

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

This site uses Akismet to reduce spam. Learn how your comment data is processed.