C++中的std::bind

关于std::bind 的一些内容。大体上是翻译自http://www.cplusplus.com/reference/functional/bind/

std::bind 位于头文件<functional>中,可以用于绑定函数的参数,从而将一个可调用对象转化为一个新的可调用对象,可以起到函数适配器的作用。bind函数的原型如下:

1
2
template <class Fn, class... Args> /* unspecified */ bind (Fn&& fn, Args&&... args);
template <class Ret, class Fn, class... Args> /* unspecified */ bind (Fn&& fn, Args&&... args);

bind会返回一个基于fn的函数对象,并将其参数绑定到args。每个参数都可以绑定到一个值或者占位符(placeholder)。如果绑定到值,则调用返回的函数对象时,总是会使用该绑定的值作为参数。如果绑定到占位符,调用返回的函数对象时,将会将传入的参数按照定义的占位符指定的顺序转发给原函数。

调用返回的函数对象,会得到与fn相同的返回值,除非显式地指定了返回类型Ret,注意Ret只是一个模板参数,不能够通过函数的参数隐式推导。

返回的函数对象有以下的特性:

  • 调用的返回值与fn使用绑定的参数(或使用占位符时参数转发)时返回值相同。
  • 对于第一种情况,返回的函数对象可能会有一个result_type成员,如果Fn是一个指向函数的指针,或成员函数,则result_type被定义为其返回类型的代名,否则如果存在Fn::result_type的话会被定义为Fn::result_type
  • 对于第二种情况,其会有一个成员result_type,定义是Ret的代名。
  • 可以移动构造(move-constructible),并且如果它的所有参数都可以拷贝构造(copy-constructible),它也可以拷贝构造。如果FnArgs...的退化类型(decay type)的构造函数都不会抛出异常,则其两种构造函数也都不会抛出异常。

参数说明:

  • fn:一个函数对象、指向函数的指针或指向成员的指针。Fn的退化类型应当是可以使用fn来移动构造的。
  • args…:要绑定的参数列表,可以是值或者占位符。Args...的退化类型应当可以分别从args...对应参数移动构造而来,如果其中任意参数的退化类型是reference_wrapper,则会绑定它的引用。

返回值:

一个函数对象,当调用它时,则会使用绑定的参数调用fn。如果fn是一个成员的指针,则返回的函数对象需要的第一个参数应当是该类的对象(或它的引用或指针)。

以下是一个较完整的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// bind example
#include <iostream> // std::cout
#include <functional> // std::bind
// a function: (also works with function object: std::divides<double> my_divide;)
double my_divide (double x, double y) {return x/y;}
struct MyPair {
double a,b;
double multiply() {return a*b;}
};
int main () {
using namespace std::placeholders; // adds visibility of _1, _2, _3,...
// binding functions:
auto fn_five = std::bind (my_divide,10,2); // returns 10/2
std::cout << fn_five() << '\n'; // 5
auto fn_half = std::bind (my_divide,_1,2); // returns x/2
std::cout << fn_half(10) << '\n'; // 5
auto fn_invert = std::bind (my_divide,_2,_1); // returns y/x
std::cout << fn_invert(10,2) << '\n'; // 0.2
auto fn_rounding = std::bind<int> (my_divide,_1,_2); // returns int(x/y)
std::cout << fn_rounding(10,3) << '\n'; // 3
MyPair ten_two {10,2};
// binding members:
auto bound_member_fn = std::bind (&MyPair::multiply,_1); // returns x.multiply()
std::cout << bound_member_fn(ten_two) << '\n'; // 20
auto bound_member_data = std::bind (&MyPair::a,ten_two); // returns ten_two.a
std::cout << bound_member_data() << '\n'; // 10
return 0;
}

REFERENCE

http://www.cplusplus.com/reference/functional/bind/