boost中有一个bind库, 可以说是一个最为实用的tools了, 但是它与boost结合的有些紧密,而且其中的一些功能并不是很常用,就算将它bcp出独立的库也是一个不小的负担。如果在你的项目中不打算有boost库的痕迹但是又想使用bind的强大功能,那就来看看它吧。
一个一个超小型的bind库, 它实现了大部分boost::bind的功能, 只是将名字空间由boost 变换为 bi 。如果使用了一般的使用中通常可以将
boost::bind(my_fun(), _1,_2)(234, "hello world"); //形式替换为 bi::bind(my_fun(), _1, _2)(234, "hello world");
int f(int a, int b) { return a + b; } int g(int a, int b, int c) { return a + b + c; }bind(f, 1, 2) 会产生一个函数对象,它将f(1, 2)这样的函数调用包装到了自身,同样,bind(g, 1, 2, 3)() 的形式调用等价于 g(1, 2, 3)。
bind(f, _2, _1)(x, y); // f(y, x) bind(g, _1, 9, _1)(x); // g(x, 9, x) bind(g, _3, _3, _3)(x, y, z); // g(z, z, z) bind(g, _1, _1, _1)(x, y, z); // g(x, x, x)注意,最后一个示例中,由 bind(g, _1, _1, _1) 生成的函数对象不包含对第一个参数以外的任何参数的引用,但是它仍然能使用一个以上的参数。所有多余的参数被悄悄地忽略,就像在第三个示例中,第一和第二个参数被忽略。
int i = 5; bind(f, i, _1);一个 i 的值的拷贝被存储于bind生成的函数对象中。
int f(int, int); int main() { bi::bind(f, 1); // error, f函数f必须具备两个参数 bi::bind(f, 1, 2); // OK }这个错误的一个常见变化是忘记成员函数有一个隐含的 "this" 参数:
struct X { int f(int); }; int main() { bi::bind(&X::f, 1); // error,函数f必须具备两个参数 bi::bind(&X::f, _1, 1); // OK }和函数对象一起使用 bind
struct F { int operator()(int a, int b) { return a - b; } bool operator()(long a, long b) { return a == b; } }; F f; int x = 104; bi::bind(bi::type<int>(), f, _1, _1)(x);bi::bind库不支持 bind<int>(f, _1, _1)(x); 形式的调用, boost支持这种调用方式。
int x = 8; bind(std::less<int>(), _1, 9)(x); // x < 9bind(f, ...) 和 bind<R>(f, ...) 有什么不同
struct X { bool f(int a); }; X x; Boost::shared_ptr<X> p(new X); //自然支持 boost::shared_ptr int i = 5; bind(&X::f, x, 1)(i); // ( _internal copy of x).f(i) bind(&X::f, p, 1)(i); // ( _internal copy of p)->f(i)最后两个示例的有趣之处在于它们生成“自包含”的函数对象。bind(&X::f, x, _1) 存储 x 的一个拷贝。bind(&X::f, p, _1) 存储 p 的一个拷贝,而且因为 p 是一个 boost::shared_ptr,这个函数对象保存一个属于它自己的 X 的实例的引用,而且当 p 离开它的作用域或者被 reset() 之后,这个引用依然保持有效。
struct X { int& get(); int const& get() const; }; int main() { bi::bind( &X::get, _1 ); }这里的二义性可以通过将(成员)函数指针强制转换到想要的类型来解决:
int main() { bi::bind( static_cast< int const& (X::*) () const >( &X::get ), _1 ); }另一个或许更可读的办法是引入一个临时变量:
int main() { int const& (X::*get) () const = &X::get; bi::bind( get, _1 ); }为函数组合使用嵌套的 binds
bind(f, bind(g, _1))(x); // f(g(x))当函数对象被调用的时候,如果没有指定顺序,内部 bind 表达式先于外部 bind 表达式被求值,在外部 bind 表达式被求值的时候,用内部表达式的求值结果取代它们的占位符的位置。在上面的示例中,当用参数列表 (x) 调用那个函数对象的时候,bind(g, _1)(x) 首先被求值,生成 g(x),然后 bind(f, g(x))(x) 被求值,生成最终结果 f(g(x))。
typedef void (pf)(int); std::vector<pf> v; std::for_each(v.begin(), v.end(), bind(_1, 5));尽管在缺省情况下,第一个参数是不被求值的,而所有其它参数被求值。但有时候不需要对第一个参数之后的其它参数求值,甚至当它们是内嵌 *bind 子表达式的时候也不需要。
示例
和标准算法一起使用 bind
class image; class animation { public: void advance(int ms); bool inactive() const; void render(image & target) const; }; std::vector<animation> anims; template<class C, class P> void erase_if(C & c, P pred) { c.erase(std::remove_if(c.begin(), c.end(), pred), c.end()); } void update(int ms) { std::for_each(anims.begin(), anims.end(), ni::bind(&animation::advance, _1, ms)); erase_if(anims, bi::mem_fn(&animation::inactive)); } void render(image & target) { std::for_each(anims.begin(), anims.end(), bi::bind(&animation::render, _1, bi::ref(target))); }局限性
bi-bind 同时提供了 callback功能, 它就像是一个简化版本的 boost::function, 对一次调用行为做了抽象。
int fun1(int p2) { std::cout << "call fun1" << std::endl; return p2 * p2; } struct fun2 { fun2(int p1) { p_ = p1; } int operator()(int p2) const { return p2 * p_; } int p_; };//绑定一般函数 构造 callback
struct fun2 { fun2(int p1) { p_ = p1; } int operator()(int p2) const { return p2 * p_; } int p_; };
//假设fun2的拷贝复制的负担很大 fun2 f(23); //使用bi::ref解除对f对像的值语义调用 bi::bind(bi::ref(f), 9)(2);我没有写bi::bind的使用文档, 因为它 在这里 http://www.boost.org/doc/libs/1_49_0/libs/bind/bind.html。