std::bind function adaptor (std::bind fonksiyon uyumlandırıcısı) - 1


C++11 ile standart kütüphaneye eklenen bind fonksiyon şablonu genel amaçlı bir fonksiyon (function adapter) uyumlandırıcısıdır.  Bir fonksiyonun istenildiği sekilde çağrılma kalıbına uygun bir obje oluşturarak saklamamızı sağlayan şablon sınıfıdır. Aşağıda objenin oluşturulma biçimini daha net görebiliriz.
std::bind, standart kütüphanede önceden beri var olan, kullanımı daha zahmetli ve biraz da sorunlu olan ptr_fun, mem_fun, mem_fun_ref, bind1st ve bind2nd fonksiyon uyumlandırıcılarının yerine gelmiştir. Ve bu uyumlandırıcılar standartlar tarafından deprecated kabul edilmiştir. std::bind'ın kökeni boost::bind'a dayanmaktadır. Lambda'lar olmadan önce önemli bir eksikliği gidermesi öngörülürken lambdalarla aynı zamanda standart hale gelmiş olması biraz kıyıda/köşede kalmasına sebep olmuştur. Kullanım kolaylığından dolayı daha çok lambda'lar tercih edilmektedir. std::bind bizi doğrudan function pointer karmaşasında kurtarmakta ve std::placeholder ile parametrelerini manipüle etmemize olanak sağlamaktadır. Şimdi sırayla kullanım senaryolarına ve bize sağladığı faydaları/kolaylıkları inceleyelim.

std::bind | function pointer olarak kullanımı

std::bind fonksiyon pointer tanımlama karmaşasına girmeden kolaylıkla bir fonksiyonu sarmalamamıza olanak sağlamaktadır.

Yukarıdaki örnekte isGreater fonksiyonu gönderilecek parametreleri ile beraber sarmalanmış ve fonksiyon pointer biçiminde çağrılabilmiştir.

std::bind | partial function olarak kullanımı

Parçalı fonksiyon biçiminde kullanımdan kasıt fonksiyon argumanlarından bazılarının sabitlenmesi anlamına gelmektedir.
Yukarıdaki örnekte isGreater fonksiyonunun birinci parametresi placeholders ile dış dünya ile ilişkilendirilmiş ikinci parametre ise sabit bir değere ayarlanmıştır.

placeholders değişkenleri

std::bind'a geçilen bağlanmış placeholders::x 'lar bize 'bind' edilen fonksiyona, çağrılma esnasında çeşitli parametrelerle çağırma esnekliği sağlamaktadır. Bu sayede fonksiyonun sarmalanması sırasında tüm parametrelerin girilmesine gerek kalmamaktadır. Bir placeholder değişkenin ismi, bağlanacak argüman listesinde hangi sırada kullanılmış ise, fonksiyon nesnesi ile yapılan çağrıda bu ismin işaret ettiği x numaralı parametre, sarmalanan fonksiyonun bu sıradaki parametresine argüman olarak geçileceği anlamına gelir. Daha açıklayıcı olması için:
auto f = std::bind(func, _3, _2, _1);
f(2,4,6) 
biçimindeki örneği inceleyelim:
  • placeholders::_1 ismi bind‘a geçilen bağlanacak argümanlar listesinde üçüncü sırada kullanılmış ise oluşturulan fonksiyon nesnesi ile yapılan çağrıda kullanılan birinci argüman sarmalanan fonksiyonun üçüncü parametresine aktarılır.
  • placeholders::_2 ismi bind‘a geçilen bağlanacak argümanlar listesinde ikinci sırada kullanılmış ise oluşturulan fonksiyon nesnesi ile yapılan çağrıda kullanılan ikinci argüman sarmalanan fonksiyonun ikinci parametresine aktarılır.
  • placeholders::_3 ismi bind‘a geçilen bağlanacak argümanlar listesinde birinci sırada kullanılmış ise oluşturulan fonksiyon nesnesi ile yapılan çağrıda kullanılan üçüncü argüman sarmalanan fonksiyonun birinci parametresine aktarılır.
Şimdi yukarıdaki bilgilere göre f(2,4,6) nasıl çağrılacak dersek;
tabiki func(6,4,2) şeklinde olacaktır.

std::bind | value  & reference semantics olarak kullanımı

std::bind value semantics çalıştığından dolayı dışarıdan geçilen parametreleri value type olarak  kullanır. Yukarıda örneğin dikkat çektiği nokta fonksiyon ne kadar referans yoluyla parametre alıyor olsa da std::bind bu ival1 ve ival2 değişkenlerini referans yoluyla aktarmadığını ve program çalıştırılırsa ekrana 7, 9 sayılarının yazılacağı ilişkindir. Referans yoluyla aktarım yapabilmek için yapılması gereken aşağıdaki örnekte açıklanmıştır.
std::bind'ın referans semantics çalışmasını istiyorsak std::ref'i kullanmamız ve bu sayede ival1 ve ival2 değişkenlerini referans yoluyla aktarılacağı ve program çalıştırılırsa ekrana 49, 81 sayılarının yazıldığı görülecektir.

Note:

  • place_holders nesneleri bağlanacak argümanlar listesinde birden fazla yerde de kullanılabilir:

std::bind(squareof, std::placeholder::_1, std::placeholder::_1)

decltype specifier (decltype fonksiyonu) - 1

07:25 ,
decltype, C++11 ile gelen ve çoğunlukla generic programlamada kullanılan özelliklerden biridir. Türden bağımsız (generic) olarak yazılan kodlarda, bir ifadenin türünün derleme zamanında derleyici tarafından yapılacak bir çıkarımla anlaşılması gereken durumlarda yardımımıza yetişmektedir.  Kısaca kendisine verilen ifadenin türünü döndürür. Aynı sizeof() gibi derleme zamanında işini yapar. Aşağıdaki bir değişken için tür bildirimi örneğini görebiliriz: 

Basit bir decltype ile değişken bildirim örneği
decltype(...) ve decltype((...)) farklı anlamlara gelir. Eğer int param = 3; bildiriminin ardından decltype(param) ifadesi int sonucunu verir. decltype((param ))  ifadesi ise int& sonucunu verir. Parantezlere ilişkin bu kurala dikkat edilmesi gerekir.

decltype & auto

ilk bakışta benzer işler yaptığı izlenimi veren bu iki kavram aslında birbirinden farklı biçimde çalışmaktadır. decltype eğer bir değişkene uygulanmıyorsa çıkarım yapar ve çıkarım yaparken auto'nun tür belirleme kurallarına uymaz. Bu sebeple ikisinin uyguladığı çıkarım kurallarını ayrı ayrı bilmek gerekmektedir. 

const int bir değişkeni nasıl algıladıklarına ilişkin örnek aşağıdadır:
const'luk söz konusu olduğunda decltype ile auto farklılığı örneği
Yukarıdaki farklılığa değineceğimiz ilk nokta const (top level const) olması durumunda auto için bunun bir anlamı olmasa da decltype için const'luk dikkate alınacaktır ve;
  • aval int türünden
  • dval const int türünden bildirilecektir.
(const) int& bir değişkeni nasıl algıladıklarına ilişkin örnek aşağıdadır:
referans'lık söz konusu olduğunda decltype ile auto farklılığı örneği
Yukarıdaki farklılığa değineceğimiz ilk nokta referans olması durumunda auto için bunun bir anlamı olmasa da decltype için referans'lık dikkate alınacaktır ve;
  • aval int türünden
  • dval const int& türünden bildirilecektir.
bir container elemanını nasıl algıladıklarına ilişkin örnek aşağıdadır:
container söz konusu olduğunda decltype ile auto farklılığı örneği
Yukarıdaki farklılığa değineceğimiz ilk nokta vector[0] int türünden olduğu için auto için sadece bunun bir anlamı olacak, decltype için ise vectörün operator[] geri dönüş türü (std::vector<int>::operator[](size_type) const) dikkate alınacaktır ve;
  • aval int türünden
  • dval const int& türünden bildirilecektir.
bir r-value değişkeni nasıl algıladıklarına ilişkin örnek aşağıdadır:
r-value referans'lık söz konusu olduğunda decltype ile auto farklılığı örneği

Yukarıdaki farklılığa değineceğimiz ilk nokta r-value referans olması durumunda auto için bunun bir anlamı olmasa da decltype için r-value referans'lık dikkate alınacaktır ve;
  • aval int türünden
  • dval int&& türünden bildirilecektir.

Son olarak decltype içerisine  değişken dışında ifade yazılması durumunda işlenecek kurallar aşağıdaki gibidir:
decltype(expr)
biçiminde bir kullanımda expr bir değişken değil ise, T ise bu ifadenin türü olsun;
Eğer expr bir lvalue (sol taraf değeri) ise decltype(expr) T& olarak ele alınır.
Eğer expr bir xvalue ise decltype(expr) T&& olarak ele alınır.
Eğer ifade bir prvalue (saf sağ taraf değeri) ise decltype(expr) T türü olarak ele alınır.