algoritmaların üye işlevleri çağırması

Sınıf nesneleri ya da sınıf göstericileri tutan bir kabımız var. Bu kapta tutulan öğelerin tamamı ya da belirli bir aralığı için öğelerin ait olduğu sınıfın static olmayan bir üye işlevini çağırmak istiyoruz. Gelin ne demek istediğimizi bir örnekle gösterelim:

Boş yorum satırı olan yerlerde başka kodlar olduğunu ama o kodların şimdilik bizi ilgilendirmediğini düşünelim. main işlevi içinde tanımlanan svec isimli vector ‘de içinde 100 tane string nesnesi tutuluyor. Bu stringlerin kaç tanesinin boş olduğunu saymak amacıyla standart count_if algoritmasına çağrı yapmak istiyoruz. Bir string’in boş olup olmadığını da string sınıfının empty isimli üye işleviyle sınamak istiyoruz:

count_if algoritmasına global bir işlev ya da bir işlev nesnesi (functor) gönderebiliriz ama bir sınıfın üye işlevini doğrudan bir algoritmaya gönderme olanağımız yok. Ancak bunu gerçekleştirmek için elimizde birçok araç var. Örneğin count_if algoritmasının son parametre değişkenine bir lambda ifadesi göndermeyi tercih edebiliriz:

count_if algoritmasının son parametre değişkenine bir lambda ifadesi gönderdik. Derleyici bir lambda ifadesini, bu ifadeden yola çıkarak tanımladığı bir sınıf türünden (closure type) bir geçici nesne (closure) oluşturma ifadesine dönüştürür. lambda ifadesinde küme parantezleri içinde yer alan işlev tanımı aslında derleyicinin yazacağı sınıfın üye operatör işlevinin kodudur. Yukarıdaki örneğimizde count_if algorimasına gönderilen aralıktaki her nesne,bu işleve argüman olarak gönderilecek, işlev de parametresine çekilen string nesnesinin empty işlevini çağıracak.

Bu amaçla standart kütüphanenin functional başlık dosyasında yer alan ve C++11 standartlarıyla gelen mem_fn işlev uyumlandırıcısını da kullanabiliriz:

memfn işlev uyumlandırıcısından elde edilen functor nesne, string sınıfının empty üye işlevini sarmalıyor ve parametresine aktarılan string nesnesini *this olarak kullanıyor.  Kapta tutulan öğeler string göstericileri olsa da mem_fn işlevini yine aynı şekilde kullanabiliriz:

Kapta akıllı gösterici nesnelerinin tutulması durumunda yine mem_fn uyumlandırıcısını kullanabiliyoruz.

Aynı işi C++11 ile gelen bind genel işlev uyumlandırıcısı ile de gerçekleştirebilirdik.

bind işlevinin birinci parametresine sarmalanacak üye işlevin adresini geçiyoruz. bind işlevinin ikinci parametresine geçilen, std isim alanı içindeki placeholders isim alanı içinde tanıtılan _1 ismi sınıfın üye işlevine geçilecek sınıf nesnesini temsil ediyor.
Kap içinde gösterici ya da akıllı gösterici tutulması durumunda da bind işlevini yine aynı şekilde kullanabiliyoruz:

Peki ya algoritmanın çağıracağı işlevin bir ya da birden fazla parametre değişkeni varsa? Aşağıdaki kodu inceleyin:

main işlevi içinde tanımlanan avec isimli vector nesnesinin tuttuğu tüm A sınıfı nesneleri için sınıfın int parametreli func isimli üye işlevinin ival değeriyle çağrılması isteniyor:

Bu işi bir algoritma kullanmadan doğrudan aralık tabanlı bir for döngüsü ile yapabilirdik, değil mi?

Aynı işi şimdi de for_each algortimasına yaptıralım. lambda ifadesi kullanırsak işimiz yine kolay:

Şimdi de aynı iş için bind işlev uyumlandırıcısını kullanalım:

Şimdi de aşağıdaki koda bakalım:

avec isimli vector nesnesinin tuttuğu A nesneleri için for_each algoritmasını kullanarak sınıfın int parametreli func işlevinin ival değeriyle çağrılması gerekiyor.  Ancak func işlevi yüklenmiş; hem int hem de double parametreli func işlevleri var. Aralık tabanlı for döngüsü kullanılması durumunda bir sorun yok. Derleyici hangi func işlevinin çağrıldığını işleve gönderilen arguman olan ifadenin türünden anlayabilir:

Algortimaya lambda gönderilmesi durumunda da bir sorun olmayacak:

Ancak bind doğrudan işlevinin kullanılması durumunda bir sentaks hatası oluşacak:

Sentaks hatasının nedeni çift anlamlılık (ambiguity). Derleyicinin, A sınıfının hangi mfunc işlevine bağlama yapıldığının çıkarımını yapma olanağı yok. Kodlayıcı bind uyumlandırıcısını kullanmakta ısrarlıysa tür dönüştürme işleciyle istediği işlevin adresinin türüne dönüşüm yapmalı:

Böyle bir kod yazmayı tercih eder miydiniz?

Örneklerden de görüldüğü gibi, bir algoritmanın bir sınıfın üye işlevini çağırması gerektiğinde çoğu zaman en uygun seçenek lambda kullanımı.

Necati Ergin

C ve Sistem Programcıları Derneğinde eğitmen olarak çalışıyor.

Bunlar da ilginizi çekebilir

Bir Cevap Yazın

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

Kod Eklemek İçin Okuyun