boost::bind()用来将一个函数或函数对象绑定某些参数,返回值是一个函数对象。
它提供一个任意的函数对象(仿函数)、函数、函数指针、成员函数指针。
上代码:
#include <boost/bind.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
void add(int i, int j)
{
std::cout << i + j << std::endl;
}
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);
std::for_each(v.begin(), v.end(), boost::bind(add, 10, _1));
}
上述代码中bind绑定了一个一元函数对象。
add()
函数要求两个参数,两个参数都必须传递给boost::bind()
。 第一个参数是常数值10,而第二个参数则是一个怪异的 _1。
_1 被称为占位符(placeholder),定义于 Boost.Bind。 除了 _1,Boost.Bind 还定义了_2 和 _3。 对于 _1,
boost::bind()
返回一个一元函数,即有且只有一个参数。
当这个程序执行时,std::for_each()
对容器 v 中的每一个元素调用该一元函数。 元素的值通过占位符_1 传入到一元函数中。 这个占位符和常数值被进一步传递到 add()
函数。 通过使用这种机制,std::for_each()
只看到了由boost::bind()
所定义的一元函数。 而 boost::bind()
本身则只是调用了另一个函数,并将常数值或占位符作为参数传入给它。有点罗嗦。
上述代码有点别扭,对每个元素加10,为什么不是两个参数呢?因为std::for_each()
要求一个一元函数作为其第三个参数。
下面看bind的二元函数用法:
#include <boost/bind.hpp>
#include <vector>
#include <algorithm>
#include <iostream>
bool compare(int i, int j)
{
return i > j;
}
int main()
{
std::vector<int> v{1, 3, 2};
std::sort(v.begin(), v.end(), boost::bind(compare, _1, _2));
for (int i : v)
std::cout << i << '\n';
}
std::sort()
算法以容器
v 的两个元素来调用该函数,并根据返回值来对容器进行排序。
如果compare()为true则swap()
,容器将被按降序排列。但是,由于
compare()
本身就是一个二元函数,所以使用
boost::bind()
确是多余的。可以直接这么写:
std::sort(v.begin(), v.end(), compare);不过用bind可以方便的反向排序:
std::sort(v.begin(), v.end(), boost::bind(compare, _2, _1));只改变占位符的位置。但是这种先2后1的传参方式还是不用为好。
那么问题来了,看下面的代码—— boost::bind是怎么区分类成员函数和全局函数的?
class ClassA {
public:
void test(int, int){}
}
void mytest(ClassA* pObj, int, int) {}
typedef boost::function<void (int, int)> func;
func f1 = boost::bind(ClassA::test, this, _1, _2);
func f2 = boost::bind(mytest, pObj, _1, _2);
关于bind的内部原理,
下面的示例程序说明了一切:
#include <stdio.h>
template<typename... ARGS>
void bind(void (*func)(ARGS...), ARGS... args)
{
printf("plain function\n");
func(args...); // std::forward<> 从略。
}
template<typename CLASS, typename... ARGS>
void bind(void (CLASS::*func)(ARGS...), CLASS* clz, ARGS... args)
{
printf("member function\n");
(clz->*func)(args...);
}
template<typename CLASS, typename... ARGS>
void bind(void (CLASS::*func)(ARGS...) const, const CLASS* clz, ARGS... args)
{
printf("const member function\n");
(clz->*func)(args...);
}
void foo(int arg)
{
printf("foo %d\n", arg);
}
class Bar
{
public:
void write(double arg)
{
printf("Bar::write %f\n", arg);
}
void read(long arg) const
{
printf("Bar::read %ld\n", arg);
}
};
void zoo(Bar* x)
{
printf("zoo %p\n", x);
}
int main()
{
bind(foo, 123);
Bar bar;
bind(&Bar::write, &bar, 3.14);
bind(&Bar::read, &bar, 42L);
bind(zoo, &bar);
}
这是 Partial Template Specialization技术,即模板的"偏特化"或叫"部分特化"。