2015-05-27 74 views
0

我有以下代碼:使用Boost適配器用的std :: bind表達式

#include <boost/range/adaptor/transformed.hpp> 
#include <boost/range/algorithm.hpp> 

#include <iostream> 
#include <functional> 
#include <memory> 

struct A { 
    A() = default; 
    A(const A&) = delete; 
    A& operator=(const A&) = delete; 
}; 

struct B { 
    B() = default; 
    B(const B&) = delete; 
    B& operator=(const B&) = delete; 

    int foo(const A&, int b) { 
     return -b; 
    } 
}; 

int main() { 
    A a; 
    auto b = std::make_shared<B>(); 
    std::vector<int> values{1, 2, 3, 2}; 

    using std::placeholders::_1; 
    auto fun = std::bind(&B::foo, b.get(), std::ref(a), _1); 
    int min = *boost::min_element(values | boost::adaptors::transformed(fun)); 
    std::cout << min << std::endl; 
} 

當我嘗試編譯它,鐺提供了以下錯誤消息(全光輸出here):

/usr/local/include/boost/optional/optional.hpp:674:80: error: object of type 'std::_Bind<std::_Mem_fn<int (Base::*)(const A &, int)> (Base *, std::reference_wrapper<A>, std::_Placeholder<1>)>' cannot be assigned because its copy assignment operator is implicitly deleted 

看來,雖然綁定對象有一個拷貝構造函數,但它的拷貝賦值操作符被刪除。如果我嘗試使用lambda代替bind,我會得到相同的錯誤。

  1. 這是C++ 11標準,libstdC++實現還是Boost適配器實現中的錯誤?

  2. 這是最好的解決方法是什麼?我可以把它包裝成std::function。看來boost::bind也有效。哪個更有效率,還是真的很重要?

+0

2)'boost :: bind'比'std :: function'效率更高 – David

回答

3

這裏的問題:

  1. 該標準不要求std::bind的返回值是複製分配;只移動可構造的(如果所有綁定對象也是可複製構造的,則複製可構造)。對於lambdas,他們的複製分配操作符需要被刪除。

  2. 範圍適配器實際使用transform_iterator,所以函數對象被存儲在迭代器中。

  3. 迭代器必須是可複製賦值的,min_element試圖做到這一點,並且你的程序爆炸了。

隨着lambda表達式的C++ 11的擴散,我會打電話給這與Boost庫,這不是設計時考慮拷貝構造,但並非複製分配函數對象的問題。

其實我建議包裹導致函數對象的reference_wrapper

int min = *boost::min_element(values | boost::adaptors::transformed(std::ref(fun))); 

這也節省了每次迭代器拷貝製作仿函數的額外副本的費用。

在列出的兩個選項中,boost::bind應該更高效,因爲它不必進行類型擦除。

+0

謝謝,參考包裝函數的工作原理。實際上,在這種情況下,我覺得最好包裝一個lambda。 – petersohn

相關問題