Understanding std::function and std::bind

9

我正在尝试使用std::function和std::bind,但是我发现了一些不直观的事情,我希望更好地理解它。

举个例子:

void fun()
{
}

void hun(std::string) 
{ 
}

int main()
{

   function<void(int)> g = &fun; //This fails as it should in my understanding.

   function<void(int)> f = std::bind(fun); //This works for reasons unknown to me     
   function<void(int, std::string)> h = std::bind(hun); //this doesn't work

return 0;
}

如何将 function<void(int)> 绑定到一个返回类型为 void() 的函数中。 然后我可以调用 f(1) 并获得 fun()。 我想了解这是如何实现的。 进入 Microsoft Visual Studio 2012 的实现让我陷入了一片难以阅读的宏定义海洋,所以我在这里提出了这个问题。


我正在使用vs2012 Express版。 - Alex
可以使用 clangg++ 进行编译。+1,有趣的情况。 - awesoon
2
@KerrekSB:这是正确的行为 - 我倒是想知道你用哪个stdlib测试了std::bind(fun)版本,因为那个有bug。 :) - Xeo
@Xeo:抱歉,是我不好,我搞糊涂了我的测试用例! - Kerrek SB
显示剩余3条评论
2个回答

8

如果您不使用参数占位符(_1_2等),那么传递给从std::bind返回的函数对象的任何参数都将被丢弃。例如:

std::function<void(int)> f = std::bind(fun, std::placeholders::_1);

我按预期得到了一个(又长又难看的)错误。
对于对Standardese感兴趣的人: §20.8.9.1.2 [func.bind.bind]
template<class F, class... BoundArgs>
*unspecified* bind(F&& f, BoundArgs&&... bound_args);

p3 返回:一个弱类型转发调用包装器g(20.8.2)。调用g(u1, u2, ..., uM)的效果应该是INVOKE(fd, v1, v2, ..., vN, result_of<FD cv (V1, V2, ..., VN)>::type),其中cv代表gcv-限定符,绑定参数v1, v2, ..., vN的值和类型如下所述

p10 绑定参数v1, v2, ..., vN及其对应的类型V1, V2, ..., VN取决于从调用bind派生的类型TiD和调用包装器gcv-限定符cv,如下所示:

  • 如果TiDreference_wrapper<T>,则参数为tid.get(),其类型ViT&
  • 如果is_bind_expression<TiD>::value的值为true,则参数为tid(std::forward<Uj>(uj)...),其类型Viresult_of<TiD cv (Uj...)>::type
  • 如果is_placeholder<TiD>::value的值j不为零,则参数为std::forward<Uj>(uj),其类型ViUj&&
  • 否则,该值为tid,其类型ViTiD cv &

除此之外,即使 std::function<void(int)> f = std::bind(fun); 编译通过,实际上也无法调用 f:f(); 会编译失败。 - Peter R
1
@PeterR:显然,因为f的签名要求一个参数。 :) - Xeo

6
通过对函数模板 bind 的调用生成的转发调用包装器可以接受任意数量的额外参数,它们将被忽略。一个 bind 表达式的有效参数数量和最小签名是由其构造中使用的 placeholder 和绑定到哪个可调用参数来确定的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接