2011-07-07 16 views

Odpowiedz

140

std::bind jest dla partial function application.

Oznacza to, że masz obiekt funkcyjny f który trwa 3 argumenty:

f(a,b,c); 

chcesz nowy obiekt funkcja, która trwa tylko dwa argumenty, zdefiniowana jako:

g(a,b) := f(a, 4, b); 

g jest "częściowe zastosowanie" funkcji f: środkowy argument został już określony i są jeszcze dwa do zrobienia.

Można użyć std::bind dostać g:

auto g = bind(f, _1, 4, _2); 

To jest bardziej zwięzły niż faktycznie napisanie klasy funktora, aby to zrobić.

Istnieją dalsze przykłady w artykule, do którego link. Zwykle używa się go, gdy trzeba przekazać funktorowi pewien algorytm. Masz funkcję lub funktor, który wykonuje żądaną pracę, ale jest bardziej konfigurowalny (to znaczy ma więcej parametrów) niż używa algorytm. Więc wiążą argumenty do niektórych parametrów, a resztę pozostawić do algorytmu wypełnić:

// raise every value in vec to the power of 7 
std::transform(vec.begin(), vec.end(), some_output, std::bind(std::pow, _1, 7)); 

Tutaj, pow przyjmuje dwa parametry i może podnieść do dowolnym mocy, ale wszystko zależy nam jest podnoszenie do potęgi 7.

Jako okazjonalnego użytku, które nie jest częściowe zastosowanie funkcji, bind można również zmieniać kolejność argumentów do funkcji:

auto memcpy_with_the_parameters_in_the_right_flipping_order = bind(memcpy, _2, _1, _3); 

nie polecam go używać tylko dlatego, że nie podoba API, ale ma potencjalnych praktycznych zastosowań na przykład, ponieważ:

not2(bind(less<T>, _2, _1)); 

jest mniejszy niż lub równy funkcja (zakładając całkowitą zamówienia, bla bla). Ten przykład normalnie nie jest konieczny, ponieważ istnieje już std::less_equal (używa on operatora <=, a nie <, więc jeśli nie są spójne, może być potrzebne, a także może zajść potrzeba odwiedzenia autora klasy za pomocą cluestick). Jest to rodzaj transformacji, która pojawia się, jeśli używasz funkcjonalnego stylu programowania.

+10

także przydatny dla wywołania zwrotne do funkcji składowych: 'myThread = boost :: thread (boost :: bind (& MyClass :: threadMain, this))' – rlduffy

+10

Ładne wyjaśnienie wiązania. Ale co z 'std :: function'? – RedX

+4

Twój przykład 'pow' nie kompiluje się. Ponieważ 'pow' jest przeciążoną funkcją, musisz ręcznie określić, które przeciążenie. Wiązanie nie może pozostawić go do wyprowadzenia przez wywołującego wynikowego funktora. Na przykład. 'std :: transform (vec.begin(), vec.end(), out.begin(), std :: bind ((double (*) (double, int)) std :: pow, _1, 7)) ; ' –

7

Std :: bind został wybrany do biblioteki po propozycji, aby dołączyć bind, głównie jest to specjalizacja częściowej funkcji, w której można naprawić kilka parametrów i zmienić inne w locie. Teraz jest to biblioteczny sposób tworzenia lambdas w C++.Jak odpowiedział Steve Jessop

Teraz, gdy C++ 11 obsługuje funkcje lambda, nie odczuwam żadnej pokusy, aby używać std :: bind. Wolałbym używać curry (częściowa specjalizacja) z funkcją językową niż funkcją biblioteki.

std :: obiekty funkcji są funkcjami polimorficznymi. Podstawową ideą jest, aby móc odnosić się do wszystkich obiektów wymienialnych zamiennie.

chciałbym wskazać na te dwa linki do dalszych szczegółów:

funkcji lambda w C++ 11: http://www.nullptr.me/2011/10/12/c11-lambda-having-fun-with-brackets/#.UJmXu8XA9Z8

płatnych na żądanie podmiotu w C++: http://www.nullptr.me/2011/05/31/callable-entity/#.UJmXuMXA9Z8

+3

'std :: bind' nigdy nie istniał bez lambdas - obie funkcje zostały wprowadzone w C++ 11.Mieliśmy 'bind1st' i' bind2nd', które były wyniszczonymi wersjami wiązania C++ 11. –

5

Kiedyś to dawno powrót do utworzenia puli wątków wtyczki w C++; Ponieważ funkcja brał trzy parametry można napisać jak to

Załóżmy metodę ma podpis:

int CTask::ThreeParameterTask(int par1, int par2, int par3) 

Aby utworzyć obiekt funkcyjny do wiązania trzy parametry można zrobić tak

// a template class for converting a member function of the type int function(int,int,int) 
//to be called as a function object 
template<typename _Ret,typename _Class,typename _arg1,typename _arg2,typename _arg3> 
class mem_fun3_t 
{ 
public: 
    explicit mem_fun3_t(_Ret (_Class::*_Pm)(_arg1,_arg2,_arg3)) 
     :m_Ptr(_Pm) //okay here we store the member function pointer for later use 
    {} 

    //this operator call comes from the bind method 
    _Ret operator()(_Class *_P, _arg1 arg1, _arg2 arg2, _arg3 arg3) const 
    { 
     return ((_P->*m_Ptr)(arg1,arg2,arg3)); 
    } 
private: 
    _Ret (_Class::*m_Ptr)(_arg1,_arg2,_arg3);// method pointer signature 
}; 

Teraz, aby powiązać parametry, musimy napisać funkcję wiążącą. Tak, o to idzie:

template<typename _Func,typename _Ptr,typename _arg1,typename _arg2,typename _arg3> 
class binder3 
{ 
public: 
    //This is the constructor that does the binding part 
    binder3(_Func fn,_Ptr ptr,_arg1 i,_arg2 j,_arg3 k) 
     :m_ptr(ptr),m_fn(fn),m1(i),m2(j),m3(k){} 


     //and this is the function object 
     void operator()() const 
     { 
      m_fn(m_ptr,m1,m2,m3);//that calls the operator 
     } 
private: 
    _Ptr m_ptr; 
    _Func m_fn; 
    _arg1 m1; _arg2 m2; _arg3 m3; 
}; 

, a funkcję pomocnika użyć klasy binder3 - bind3:

//a helper function to call binder3 
template <typename _Func, typename _P1,typename _arg1,typename _arg2,typename _arg3> 
binder3<_Func, _P1, _arg1, _arg2, _arg3> bind3(_Func func, _P1 p1,_arg1 i,_arg2 j,_arg3 k) 
{ 
    return binder3<_Func, _P1, _arg1, _arg2, _arg3> (func, p1,i,j,k); 
} 

i tu nam jak to nazwać

F3 f3 = PluginThreadPool::bind3(PluginThreadPool::mem_fun3( 
      &CTask::ThreeParameterTask), task1,2122,23); 

Uwaga: f3(); wywoła metodę task1-> ThreeParameterTask (21,22,23);

Dla bardziej drastyczne szczegóły ->http://www.codeproject.com/Articles/26078/A-C-Plug-in-ThreadPool-Design

3

Jednym z głównych wykorzystania funkcji i std :: std :: wiążą się jako bezpiecznych wskaźników funkcji. W Internecie jest mnóstwo artykułów wyjaśniających, w jaki sposób wskaźniki funkcyjne są przydatne w języku C/C++. Na przykład są przydatne do wdrożenia mechanizmu wywołania zwrotnego. Oznacza to, że masz pewną funkcję, której wykonanie zajmie dużo czasu, ale nie chcesz czekać na jej powrót, możesz uruchomić tę funkcję w osobnym wątku i nadać mu wskaźnik funkcji, który wywoła po zakończeniu. .

Oto przykładowy kod jak użyć tego:

class MyClass { 
private: 
    //just shorthand to avoid long typing 
    typedef std::function<void (float result)> CallbackType; 

    //this function takes long time 
    void longRunningFunction(CallbackType callback) 
    { 
     //do some long running task 
     //... 
     //callback to return result 
     callback(result); 
    } 

    //this function gets called by longRunningFunction after its done 
    void afterCompleteCallback(float result) 
    { 
     std::cout << result; 
    } 

public: 
    int longRunningFunctionAsync() 
    { 
     //create callback - this equivalent of safe function pointer 
     auto callback = std::bind(&MyClass::afterCompleteCallback, 
      this, std::placeholders::_1); 

     //normally you want to start below function on seprate thread, 
     //but for illustration we will just do simple call 
     longRunningFunction(callback); 
    } 
}; 
Powiązane problemy