2011-07-07 301 views

回答

140

std::bind用於partial function application

也就是說,假設你有一個函數對象f包含3個參數:

f(a,b,c); 

你要定義一個新的函數對象,只需要兩個參數,如:

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

g是函數f的「部分應用」:已經指定了中間參數,並且還剩下兩個參數。

您可以使用std::bind獲得g

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

這是比實際編寫一個函數子類做更加簡潔。

您鏈接到的文章中還有其他示例。當你需要傳遞一個函子給某個算法時,你通常會使用它。你有一個函數或仿函數,差不多做你想要的工作,但是比算法使用更多可配置(即有更多的參數)。所以你綁定參數的一些參數,並保留其餘的算法來填補:

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

這裏,pow有兩個參數,並能提高到任何力量,但我們關心的是提高到7

電源作爲一個偶爾使用不是局部的功能應用,bind也可以重新排序參數的函數:

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

我不建議使用它只是因爲你不喜歡的API,但它有例如潛在的實際用途,因爲:

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

是低於或相等的功能(假設總訂單,等等等等)。這個例子通常不是必須的,因爲已經有一個std::less_equal(它使用<=運算符而不是<,所以如果它們不一致,那麼你可能需要這個,你可能還需要訪問類的作者cluestick)。不過,如果您使用的是功能性編程風格,則會出現這種轉變。

+10

也很方便於回調成員函數:'MyThread的升壓= ::螺紋(升壓::綁定(&MyClass的:: threadMain,此))' – rlduffy

+10

好的解釋綁定。但是'std :: function'呢? – RedX

+4

你的'pow'例子不能編譯。由於'pow'是一個重載函數,你必須手動指定哪個超載。綁定不能讓它由函數的調用者推導出來。例如。 'std :: transform(vec.begin(),vec.end(),out.begin(),std :: bind((double(*)(double,int))std :: pow,_1,7)) ;' –

7

std :: bind在包含boost綁定的提案之後被投票到庫中,主要是部分函數專門化,其中 - 您可以修復幾個參數並在飛行中更改其他參數。現在,這是用C++編寫lambda表達式的庫方式。正如Steve Jessop回答的那樣

既然C++ 11支持lambda函數,那麼我不會再感到有任何使用std :: bind的誘惑。我寧願使用具有語言特徵的庫裏奇(部分專業化)而不是庫特徵。

std :: function對象是多態函數。基本思想是能夠互換地引用所有可調用的對象。

我想指出你這兩個環節進一步的細節:

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

調用實體在C++: http://www.nullptr.me/2011/05/31/callable-entity/#.UJmXuMXA9Z8

+3

沒有lambda表達式的'std :: bind'永遠不會存在 - 這兩個特性都是在C++ 11中引入的。我們確實有'bind1st'和'bind2nd',它們是C++ 11 bind的消毒版本。 –

5

我用它很長一段時間返回在C++中創建一個插件線程池;由於功能正在採取三個參數,你可以這樣寫

假設你的方法有簽名:

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

要創建一個函數對象綁定三個參數,你可以做這樣的

// 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 
}; 

現在,爲了綁定參數,我們必須編寫一個綁定器函數。所以,這裏有雲:

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; 
}; 

而且,一個輔助函數使用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); 
} 

,在這裏我們如何調用它

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

注:F3 ();將調用方法task1-> ThreeParameterTask(21,22,23);

更多血淋淋的細節 - >http://www.codeproject.com/Articles/26078/A-C-Plug-in-ThreadPool-Design

3

一個主要使用std ::函數和std ::綁定的是安全的函數指針。網上有大量文章解釋了函數指針在C/C++中的用處。例如,它們對於實現回調機制很有用。也就是說,你有一些函數需要很長時間來執行,但你不想等待它返回,那麼你可以在單獨的線程上運行該函數,並給它一個函數指針,它會在它完成後回調它。

下面是如何使用此一個示例代碼:

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); 
    } 
}; 
相關問題