Lambda İFADELERİ – C++11

C++11’le gelen bence en iyi özelliklerden biri de lambda ifadeleridir. Aslında yavaş yavaş nesne yönelimli programlamanın yerine fonksiyonel programlamanın (Functional Programming) alacağı öngörülüyordu. Lambda fonksiyonlar, auto anahtar kelimesiyle beraber FP ve multi-threading-concurrency’ye de ciddi manada destek verilmiş oldu. Zaten inşallah başka bir makalenin konusu olarak C++11 le gelen Thread(Boost.Thread) kütüphanesini inceleyeğiz. Şimdi lambdalara devam edelim.

Lambda fonksiyonlar aslında fonksiyon göstericileriyle (function pointers) başlayan Functorlarla devam eden gelişimin son halkası.

Sentaks:


#include <iostream>

using namespace std;

int main(int argc, char** argv) 
{    
    auto p = [] () -> string { return "Hello World";};
    
    cout << p() << endl;
   
    return 0;
}

[] : Lambda fonksiyonlar bu ifadeyle başlar. Aslında adı “capture specification”‘dır. Birkaç satır sonra neden bu adın verildiğini daha detaylı anlamış olacağız. Kısacası derleyici bu ifadeyi gördüğünde bir lambda ifadesinin başladığını anlar.
() : Bu ifade olağan fonksiyonlarda olduğu gibi parametre listesini verdiğimiz fonksiyon çağrı operatörü.
-> return value : Bu ifade ise lambda fonksiyonun geri dönüş değerini belirtir. Fakat bu ifade vermesekte derleyici geri dönüş değerini otomatik olarak tespit edecektir. Üstteki örnekte “-> string” ifadesini silsek dahi kod çalşacaktır.

Değişken Aktarımı
Lambda fonksiyonlarını bir diğer özelliği ise bulunduğu isim alanından değişkenleri kendi gövdesine enjekte edebilme yeteneğidir. Bunu hem by value hem de by reference şeklinde yapabilir. Örneğin:

[&] () {} : Bu ifade de isim alanı içerisindeki nesnelerin tümünü “by reference” olarak enjekte ederiz. Eğer örneğin [&a] () {} şeklinde yazarsak sadece ilgili değişkeni enjekte edebiliriz.

#include <iostream>

using namespace std;

int main()
{
	
	int a = 5;
	
	cout << a << endl;
	
	auto p = [&a]() { a = 6;};
	
	p();
	cout << a << endl;
}

[=] () {} : “=” ifadesi ile isim alanı içerisindeki nesneleri “by value olarak” elde ederiz. Yine aynı şekilde [=, &a] () {} şeklinde bir bildirim yaparsak a by referans olarak geri kalan değişkenler değer olarak lambda fonksiyonuna iletilir.

Lambda ve STL:
STL’de kütüphanesinde bulunan fonksiyonlarda kullanımı oldukça pratiktir. Örneğin:

#include <iostream>
#include <algorithm>

using namespace std;




int main()
{	
	vector<string> vs;
	vs.push_back("islam");
	vs.push_back("cpp");
	vs.push_back("turkiye");
	
	
	for_each(vs.begin(), vs.end(), [] (string s) { if (s == "islam") cout << s << endl;});
	
	auto p = remove_if(vs.begin(), vs.end(), [] (string s) { if (s == "cpp") return true; return false; });

	for (auto s = vs.begin(); s != p; s++)
		cout << *s << endl;
}

Peki bir lambda ifadesini başka bir fonksiyona veya sınıfa parametre olarak vermek istediğimizde nasıl bir yol izleyeceğiz. Burda imdada std::function şablon sınıfı yetişiyor. Örneğin:

#include <iostream>
#include <algorithm>

using namespace std;

class A {
private:
	string s;
	function<void (string)> handler_func;
public:
	A(function<void (string)> f) : handler_func(f), s("cppturkey.org"){}
	
	void operator ()() { handler_func(s);}
};

int main()
{	auto f = [](string s) { cout << s << endl;};
	A a(f);
	a();
}

“function<void (string)> ” ifadesi geri dönüş değeri void olan ve parametre olarakta string alan bir fonksiyon objesini belirtmektedir.

Gelecekte lambda fonksiyonlarının concurrency ve Functional Programming ile beraber daha sık kullanıldığına şahit olacağız.

Advertisements