我正在玩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)并获得乐趣()。
我想了解这是如何完成的。
进入Microsoft Visual Studio 2012的实现,让我迷失在无法理解的宏海中。所以这就是我在这里提出这个问题的原因。
答案 0 :(得分: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返回:具有弱结果类型(20.8.2)的转发调用包装器
g
。g(u1, u2, ..., uM)
的效果应为INVOKE(fd, v1, v2, ..., vN, result_of<FD cv (V1, V2, ..., VN)>::type)
,其中 cv 表示g
的 cv - 限定符以及值和绑定参数v1, v2, ..., vN
的类型按照以下规定确定。p10绑定参数
v1, v2, ..., vN
及其对应类型V1, V2, ..., VN
的值取决于从TiD
调用派生的bind
类型和调用包装器g
的 cv - 限定符 cv 如下:
- 如果
TiD
为reference_wrapper<T>
,则参数为tid.get()
,其类型Vi
为T&
;- 如果
is_bind_expression<TiD>::value
的值为true
,则参数为tid(std::forward<Uj>(uj)...)
,其类型Vi
为result_of<TiD cv (Uj...)>::type
;- 如果
j
的值is_placeholder<TiD>::value
不为零,则参数为std::forward<Uj>(uj)
,其类型Vi
为Uj&&
;- 否则,该值为
tid
,其类型Vi
为TiD cv &
。
答案 1 :(得分:6)
通过调用函数模板bind
生成的转发调用包装器可以接受任意数量的额外参数;这些都会被忽略。 bind
表达式的有效arity和最小签名由其构造中使用的placeholder
确定,以及它们绑定的可调用参数。