2012-05-27 129 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