C++11 – std::mem_fn, std::bind, std::function

C veya C++ programlama dilinde parametre olarak bir fonksiyon vermek istediğimizde veya bu fonksiyonu bir değişkene atamak istediğimizde ihtiyacımız olan özellik fonksiyon göstericileriydi (function pointers). Ama göstericiler zaten insanları korkuturken fonk. göstericilerinin o heybetli tanımı iyice korkutucuydu. 🙂

Modern C++ fonksiyon göstericileri getirdiği sınıflar ile daha modern ve kullanışlı bir hale getiriyor.

Aşağıda C stili bir fonksiyon gösterici tanımı ve çağrılması var.

#include <iostream>


int add(int a, int b)
{
    
    return a + b;
}


using namespace std;


int main(int argc, char* argv[])
{
    int (*f)(int, int) = add;
     //auto f = add; 
    
    cout << f(5, 6) << endl;
}

Aslında C++11 ile gelen özelliklerden biri olan auto anahtar sözcüğü ile bu zahmetli tanımdan kurtulabiliriz (yorum satırında örnek kullanımı görebilirsiniz). Ya da bir fonksiyona parametre olarak verilip callback olarak kullanılacaksa bu “türü” typedef anahtar sözcüğü ile daha anlaşılır hale getirebiliriz;

#include <iostream>


typedef int(*callback_add_t)(int, int);

int add(int a, int b)
{
    
    return a + b;
}


int foo(int a, int b, callback_add_t func)
{
   return  func(a, b);
}

using namespace std;


int main(int argc, char* argv[])
{
    cout << foo(5, 6, add) << endl;
}

Bu yazıda bu yaklaşımdan ziyade C++11 ile gelen fonksiyonlar üzerinde programcıyla mutlak hakimiyet sağlayan std::mem_fn, std::bind, std::function şablon sınıfları ve fonksiyonlarından bahsetmek istiyorum.

std::mem_fn:
Üye fonksiyonları sarmalayan bir fonksiyon şablon sınıfıdır. Sınıf üye fonksiyonlarını çağırmak için kullanılır.

#include <iostream>
#include <functional>


using namespace std;


struct SDummy
{
    void who_am_i()
    {
        cout << "Jackie Chan" << endl;
    }
    
    void how_old_am_i(int i)
    {
        cout << "I am " << i << "years old" << endl;
    }
    
};

int main(int argc, char** argv) 
{
    struct SDummy dummy;
    auto jchan = std::mem_fn(&SDummy::who_am_i);
    
    jchan(dummy);


    return 0;
}

mem_fn sınıfını kullanmak yerine member function pointer kullansaydık şöyle bir tanım yapmamız gerekecekti;

void (SDummy::*pMemberFunc)();

Bu fonksiyon göstericisini bir fonksiyona parametre olarak geçip kullanmak istiyorsaniz ait oldugu nesneyi de o fonksiyona parametre olarak vermeniz gerekmektedir. Ama daha kolay yollari var 🙂 .

std::bind

Adı üstünde aslında bir fonksiyonun istenildiği sekilde çağrılma kalıbına uygun bir obje oluşturarak saklamanızı sağlayan şablon sınıfıdır. Dilerseniz bu objeyi std::function sablon sınıfını da kullanarak rahatlıkla istenilen yere taşıyabilirsiniz.

#include <iostream>


using namespace std;


struct SDummy
{
    
    int operator()(int a, int b, int c, int d)
    {
        return std::max(std::initializer_list<int> {a, b, c, d}); 
    }
    
    
};

bool isGreaterThen(int a, int b)
{
    return a < b;
}

int main(int argc, char** argv) 
{
    SDummy s;
    auto f = std::bind(s, placeholders::_1, 0, placeholders::_2, placeholders::_3);
    
    cout << f(1, 2, 3) << endl;
    
    
    auto isGreaterThenFive = std::bind(isGreaterThen, 5, placeholders::_1);
    
    cout.setf(ios_base::boolalpha);
    cout << isGreaterThenFive(3) << endl;

    return 0;
}

Örneğimizde gördüğünüz gibi bir çağırılabilen bir nesneyi çeşitli parametrelerle ‘bind’ ediyoruz. ‘placeholders::n’ lar aslında bizde ‘bind’ edilen nesneye daha sonrasında, çağrılma esnasında çeşitli parametrelere çağırma esnekliği sunuyorlar. Dikkat ederseniz std::bind şablon sınıfının geri dönüş değerini kısmen gizledik aslında o bir std::function şablon sınıfı türünden bir nesne.

std::function

Evet aslında function şablon sınıfının kullanimi size fonksiyon göstericilerini hatırlatacak. Kısaca function şablon sınııi imzasını verdiğiniz fonksiyonları obje olarak muhafaza eder.

#include <iostream>


using namespace std;


struct SDummy
{
    
    void print(int a, int b, int c)
    {
        cout << "I am Dummy Struct " << a << ", "<< b << ", " << c << endl;
    }
    
    int operator()(int a, int b, int c, int d)
    {
        return std::max(std::initializer_list<int> {a, b, c, d}); 
    }
    
    
};

bool isGreaterThen(int a, int b)
{
    return a > b;
}

int main(int argc, char** argv) 
{
    std::function<bool(int, int)> f = isGreaterThen; //1
    
    cout << f (3, 5) << endl;
    
    std::function<void()> f_lambda = []() { cout << "I am lambda" << endl; };//2
    
    f_lambda();

    SDummy s;
    std::function<int(int, int, int)> maximumOne = std::bind(s, placeholders::_1, 0, placeholders::_2, placeholders::_3); //3
    
    cout << maximumOne(1, 2, 3) << endl;
        
    std::function<void(int, int)> dummyPrint = std::bind(&SDummy::print, s, placeholders::_2, 0, placeholders::_1); //4 
    
    dummyPrint(4, 5);
    
    return 0;
}

Görüldüğü üzere std::function içerisinde fonksiyonları rahatlıkla muhafaza edebiliyoruz. Örneklerde yer vermedim ama bu nesnelerin rahatlıkla parametre olarak bir başka fonksiyona veya sınıfa verllebileceği de aşikar. Onunla ilgili örnekleri de size bırakıyorum.

1′ nolu örnekte görüldüğü üzere bool(int, int) imzalı fonksiyonu direkt fonksiyon objesi içinde muhafaza edebiliyoruz. ‘2’ nolu örnekte ise yine modern cpp özelliklerinden bir lambda fonksiyonunun uygulamasını görüyoruz. ‘3’ nolu örnekte ise ‘bind’ ile özelleştirilen bir fonksiyonunun std::function içerisinde tutulmasını ve daha sonra çağrılmasını görebilirsiniz. Bu kullanım en yaygın kullanım şeklidir. ‘4’ nolu kullanımda ise bir sınıf üye fonksiyonunun std::function şablon sınıfı ile nasıl muhafaza edilebileceğini görüyoruz. Burda dikkat edilirse ikinci parametre olarak üyesi olunan sınıf türünden bir nesne parametre olarak geçiliyor. Eh geçilmesi gerekiyor ki fonksiyon çağırılabilsin tabi üye fonksiyon static değil ise.

std::end(story)

Advertisements

2 thoughts on “C++11 – std::mem_fn, std::bind, std::function

  1. Selam İslam,
    Eline sağlık güzel bir yazı olmuş. C++11 ve C++17 ile gelen özelliklere ilişkin yazılar bu ekosisteme ilişkin çok faydalı yazılar. Umarım daha sık yazı yazacak vakit bulursun. Ek olarak yurt dışında çalışmaya ilişkin ve iş bulma sürecine ilişkin deneyimlerini paylaşırsan seviniriz.

    4. örnek için
    include list
    include algorithm
    include functional

    5. örnek için
    include algorithm
    include functional

    eklemelerini yaparsan iyi olur.

    • Merhaba Can,

      Firsat buldukca yazmaya calisiyorum. Yurtdisinda cok fazla tecrubem yok ama londradaki C++ piyasasindan bahsedebilirim 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s