11 Eylül 2017 Pazartesi

std::bind

Giriş
Şu satırı dahil ederiz.
#include <functional>
Bind'in nasıl çalıştığını görsel olarak anlamak önemli. std::bind yerine lambda'yı tercih edenler çok. Açıklaması şöyle
std::bind came from boost::bind, which was necessary before we had lambdas.

Unfortunately std::bind made it into the standard at the same time as lambdas, so it was immediately almost irrelevant.
function pointer olarak kullanımı
C++11 ile gelen std::bind (kendisi boost::bind ile aynıdır) bizi function pointer karmaşasından kurtarıyor bizi.
Şöyle yaparız
int main ( void ) 
{
  D d;

  auto f = std::bind( &D::foo, _1);
  f(&d, 5);
 }
partial function olarak kullanımı
std::bind, partial function'lar için kullanılabilir.  Partial Function parametrelerden bazılarının sabit olması anlamına gelir.
"In computer science, partial application (or partial function application) refers to the process of fixing a number of arguments to a function, producing another function of smaller arity. "
Sabitleme işlemi için functor yazmak yerine, std::bind kullanmak çok daha kolay bir çözüm.

Aşağıdaki örnekte elimizde 3 tane parametre alan bir metodumuz var. 2. parametreyi 4 sabit değerine bağlamak için istiyoruz. Geri kalan parametreler için de std::placeholder'lar kullanıyoruz.
auto g = bind(f, _1, 4, _2);
Bir başka örnek şöyle
std::function<void(int)> g = std::bind(f, _1, 0) ;
std::bind ve overload
Eğer overload edilmiş iki metod varsa, derleyici genelde hata veriyor. Bu durumda derleme hatasını aşmak için iki seçeneğimiz var.
Elimizde şöyle bir sınıf olsun
class Test{
public:

    int work(){
        cout << "in work " << endl;
        return 0;
    }

    void work(int x){
        //cout << "x = " << x << endl;
        cout << "in work..." << endl;
    }
};  
1. cast yapmak
cast şöyle yapılır. cast için function pointer tanımı yerine auto kullanmak çok daha iyi.
Test test;

// only overload resolution required here 
auto fp = static_cast<int (Test::*)()>(&Test::work);

// type is now unambiguous and overload resolution is already done
std::function<void()> f = std::bind(fp, &test);
cast kodları çok karışık haller alabiliyor. Okunurluğa dikkat etmek önemli.
std::function<void()>f=std::bind(static_cast<int(Test::*)()>(&Test::work), &test);
typdef kullanmak ta okunurluğu artırmıyor.
Test test;
typedef int(Test:: *WKPtr)(void);
WKPtr p = &Test::work;
std::function<int()> f = std::bind(p, &test);
f();

2. std::bind yerine direkt lambda kullanmak.
Şöyle yapmak bazen std::bind'dan daha kolay olabiliyor.
auto fp = [&t]() { t.test()};

std::bind return type
std::bind için ilginç bir şekilde return type tanımlanmamış.
template< class F, class... Args >
/*unspecified*/ bind( F&& f, Args&&... args );

std::bind ve value semantics
std::bind normalde value semantics ile çalışır yani yani dışarıdan geçilen parametreleri value type olarak  kullanır.
int f(double x);

auto fun = std::bind(f, 1.0); // stores a copy, not a reference to a temporary
fun();
std::bind ve reference semantics
Eğer reference semantics kullanmak istersek std::ref kullanmamız gerekir. std::ref bir std::reference_wrapper nesnesi döner.
double t=1.0;
auto fun = std::bind(f, std::ref(t));
Eğer ref olamıyorsa derleme hatası alırız.
struct A
{
  A() = default;
  A(const A&) = delete;
  A& operator =(const A&) = delete;

   void foo() const
  {}
};

int main()
{
  A a;
  std::bind(&A::foo, &a); // ok
  std::bind(&A::foo, a);  // error

  return 0;
}

Hiç yorum yok:

Yorum Gönder