問題提出:
我寫了一個函數,它需要使用一個生成整數隨機數的隨機數發生器作為參數。然後寫了一個函數來根據參數生成不同分布的隨機數發生器,供前一個函數使用。我調用了boost庫的一些基於特定概率分布的隨機數生成函數,但是有很多函數的結果是double型的。
我的函數將隨機數發生器定義為boost::function<int()>類型。很明顯那些生成double的函數不能直接通過bind operator()的方式得到,而需要類型轉換。而這個使用bind/function的嵌套調用就比較麻煩了。
假設我有兩個函數:
[cpp]
int trans(double);
double gen();
int trans(double);
double gen();
我希望的結果是得到一個函數對象:它使用gen生成原始數字,然後用trans函數把它轉成整形返回;即得到一個這樣的函數:
[cpp]
int fun(){
return trans(gen());
}
int fun(){
return trans(gen());
}
我這裡還是無參數的,所以不好使用lambda表達式。
最終方案與要點:
這個問題解決好久,心酸啊,過程就略過了,直接說最終方法。
假設使用前面的函數聲明,那麼這個函數對象應該這麼生成:
[cpp]
boost::function<int()> fun=boost::bind(trans,boost::bind(gen));
boost::function<int()> fun=boost::bind(trans,boost::bind(gen));
其中要使用兩次bind!
內層的那個看似沒什麼用,但是如果不適用它的話,boost不會以為我們要綁定的第一個參數是一個函數,而是以為我們要綁定一個具體的值,這個數字的值由這個gen函數產生。這時編譯器會報“無法將double(void)類型轉換為double類型”的錯誤。
同樣的其他參數形式的(需要使用lambda庫)、多層的函數嵌套綁定,都應該注意要把內層的函數通過bind變成一個可傳遞的對象,而不能直接寫函數名!
bind綁定的各個東西都是對象(包括基本數據類型),是不支持把參數直接綁定為函數的,要這邊做必須先把函數變成可以自由傳遞的對象!
另外不要以為你的參數已經是函數對象了就可以直接寫了,還要再寫bind(),具體原因還不清楚。
其他經驗:
1,static_cast<T>()是運算符而不是函數!所以不能綁定。
2,boost/lambda/casts.hpp提供的ll_static_cast<T>雖然是函數,但是需要注意的是它是有兩個模板參數的模板函數,在綁定的時候我們不能給出參數的實際類型(外側的bind函數給ll_static_cast提供的是funnction<int()>的類型而不是int),因而也不能使用ll_static_cast,要自己寫轉換函數。
3,bind和lambda/bind有沖突,而且很多功能重疊,用一個就好了。