2012-05-27 171 views
21

我在檢測爲什麼這是不編譯的麻煩。我有一些lambda函數返回基於一些參數的std::functionstd ::綁定綁定函數

我已經收窄我的問題,這個段(不使用lambda表達式,但完全再現我的錯誤):

#include <functional> 
#include <iostream> 


struct foo { 
    template<class T> 
    void bar(T data) { 
     std::cout << data << "\n"; 
    } 
}; 

void some_fun(const std::function<void(int)> &f) { 
    f(12); 
} 

int main() { 
    foo x; 
    auto f = std::bind(&foo::bar<int>, x, std::placeholders::_1); 
    auto w = std::bind(some_fun, f); 
    w(); 
} 

w()呼叫產生那些可愛的gcc錯誤輸出中的一個,其中我無法弄清楚發生了什麼問題。這是GCC 4.6.1附和錯誤:

g++ -std=c++0x test.cpp -o test 
test.cpp: In function ‘int main()’: 
test.cpp:20:7: error: no match for call to ‘(std::_Bind<void (*(std::_Bind<std::_Mem_fn<void (foo::*)(int)>(foo, std::_Placeholder<1>)>))(const std::function<void(int)>&)>)()’ 
/usr/include/c++/4.6/functional:1130:11: note: candidates are: 
/usr/include/c++/4.6/functional:1201:2: note: template<class ... _Args, class _Result> _Result std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args&& ...) [with _Args = {_Args ...}, _Result = _Result, _Functor = void (*)(const std::function<void(int)>&), _Bound_args = {std::_Bind<std::_Mem_fn<void (foo::*)(int)>(foo, std::_Placeholder<1>)>}] 
/usr/include/c++/4.6/functional:1215:2: note: template<class ... _Args, class _Result> _Result std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args&& ...) const [with _Args = {_Args ...}, _Result = _Result, _Functor = void (*)(const std::function<void(int)>&), _Bound_args = {std::_Bind<std::_Mem_fn<void (foo::*)(int)>(foo, std::_Placeholder<1>)>}] 
/usr/include/c++/4.6/functional:1229:2: note: template<class ... _Args, class _Result> _Result std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args&& ...) volatile [with _Args = {_Args ...}, _Result = _Result, _Functor = void (*)(const std::function<void(int)>&), _Bound_args = {std::_Bind<std::_Mem_fn<void (foo::*)(int)>(foo, std::_Placeholder<1>)>}] 
/usr/include/c++/4.6/functional:1243:2: note: template<class ... _Args, class _Result> _Result std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args&& ...) const volatile [with _Args = {_Args ...}, _Result = _Result, _Functor = void (*)(const std::function<void(int)>&), _Bound_args = {std::_Bind<std::_Mem_fn<void (foo::*)(int)>(foo, std::_Placeholder<1>)>}] 

這裏,f應該有一些可調用的對象,它接受一個int作爲參數,並使用它調用。另一方面,w只是一個可調用的對象,它調用some_fun(f),這是上面提到的可調用對象,它具有some_fun的參數期望的簽名。

我錯過了什麼嗎?我可能不知道如何實際混合std::bindstd::function

+2

它似乎工作時,你用'std :: function '替換汽車爲f。 – Lalaland

+2

這可能不是你的問題的答案..但你有沒有考慮過使用C++ 11(使std :: bind不必要)的原生lambda函數? – coldfix

+4

在Boost中,我們對這種情況有'保護',但似乎沒有達到標準。 –

回答

21

std::bind表達式,像他們的boost::bind前輩,支持一種類型的組合物的操作。您的w表達是大致相當於以這種方式

auto w=std::bind(some_fun, std::bind(&foo::bar<int>, x, std::placeholders::_1)); 

嵌套結合被解釋爲

  1. 計算的x.bar<int>(y)的值,其中y是傳遞到所得的算符的第一個參數。
  2. 將結果傳入some_fun

但是x.bar<int>(y)返回void,不是任何函數類型。這就是爲什麼這不編譯。

正如K-ballo指出的那樣,使用boost::bind,您可以使用boost::protect修復此問題。正如Kerrek SB和ildjarn指出的那樣,解決此問題的一個方法是:請勿對f使用auto。你不想f有一個綁定表達式的類型。如果f有其他類型,則std::bind將不會嘗試應用功能組合規則。您可能,例如,給f類型std::function<void(int)>

std::function<void(int)> f = std::bind(&foo::bar<int>, x, std::placeholders::_1); 
auto w = std::bind(some_fun, f); 

由於f沒有字面上有一個綁定表達式的類型,std::is_bind_expression<>::value將是f的類型假的,所以在該std::bind表達第二行只是逐字傳遞值,而不是試圖應用函數組合規則。

-3

some_fun想要參數類型const std::function<void(int)> &

std :: bind返回「未指定類型T的函數對象」(查看提供的鏈接,「返回值」部分),您嘗試以some_fun參數傳遞。

看來這會導致問題,因爲這個參數類型不是預期的。

看:http://en.cppreference.com/w/cpp/utility/functional/bind

+2

這根本就不是根本問題 - 「std :: is_bind_expression <>'它的行爲是。 – ildjarn