1.看BOOST_BIND源码推导的具体过程:
(1). bind是一个函数,返回值是一个 bind_t 对象,然后再调用bind_t对象的 operator() 函数
(2).看下面的代码,list_av_2实际上是一个包装类,list_type的实际值见下面的代码:
template<class F, class A1, class A2>
_bi::bind_t<_bi::unspecified, F, typename _bi::list_av_2<A1, A2>::type>
BOOST_BIND(F f, A1 a1, A2 a2)
{
typedef typename _bi::list_av_2<A1, A2>::type list_type;
return _bi::bind_t<_bi::unspecified, F, list_type> (f, list_type(a1, a2));
}
template<class A1, class A2> struct list_av_2
{
typedef typename add_value<A1>::type B1;
typedef typename add_value<A2>::type B2;
typedef list2<B1, B2> type;
};
所以bind_t对象的成员有:f 和 listN(这里的N指的是参数的个数)
(3).在调用 bind_t 的operator()函数的时候,又会有一个listN,所以一共有两个listN。
在下面的代码中又会发现一个变量a,它也是listN
template<class A1, class A2> result_type operator()(A1 & a1, A2 & a2)
{
list2<A1 &, A2 &> a(a1, a2);
BOOST_BIND_RETURN l_(type<result_type>(), f_, a, 0);
}
(4)在bind_t的operator() 函数里面又调用了 listN的 operator函数:
下面两个listN同时出现了,一个以this的形式出现,一个以 变量a的形式出现:
注意:unwrap有很多重载函数
template<class R, class F, class A> R operator()(type<R>, F & f, A & a, long)
{
return unwrapper<F>::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_]);
}
(5)然后又会调用listN的operator[]函数,这里需要注意的是operator[]会有很多重载函数
operator[]的作用是,右站位符得到具体的参数值。
2.bind函数的应用举例:
(1)对于普通函数
void f(int a, int b)
{
cout<<a<<b<<endl;
}
向它绑定参数:
bind(f,3,4)(); //相当于f(3,4)
bind(f,_1,3)(4);//相当于 f(4,3), _1在这里是占位符(plave holder), 它对应与第二个括号里面的参数,_1表示第一个参数,_2表示第二个参数,一共可以到_9
bind(f,_2,_1)(3,4); //相当于f(4,3), 可以看出这里占位符的顺序是可以变的。
更具上面的代码分析,因为函数的参数个数是 bind_t 对象的 listN决定的,所以第二个 listN的个数可以有多个,只要符合要求就行:
ex:
bind(f,_1,_3)(1,2,3,4); //f(1,3)
bind(f, _1,_1)(1,2,3);//f(1,1)
int f1()
{
return 1;
}
int a = boost::BOOST_BIND(f1)();
(2).结构体或者类的成员函数的绑定:
绑定operator()函数:
struct Func {
void operator()(int x) {
cout << x << endl;
}
} f;
绑定的时候可能要指出返回值的类型:
boost::bind<void >(f, 3)(); //指出返回值的类型 void
绑定其它成员函数:
struct A {
void func(int x, int y) {
cout << x << "," << y << endl;
}
};
A a;
A* pa = new A; //指针
boost::shared_ptr<A> ptr_a(pa); //智能指针.
现在 要向像 A::func 这样的非静态成员函数绑定.
若A::func有n个参数, 则 bind 要有 n+2 个参数: 指向成员函数fun的指针, 绑定到this的对象, n个参数.
如:
boost::bind(&A::func, a , 3, 4)(); //输出 3, 4
boost::bind(&A::func, pa , 3, 4)(); //输出 3, 4
boost::bind(&A::func, ptr_a , 3, 4)(); //输出 3, 4
同样可以用 _1 这样的占位符. 如:
boost::bind(&A::func, _1, 3, 4)(ptr_a);//输出 3, 4
和function联合使用:
boost::function<void*(void*)> threadRoutine;
threadRoutine = boost::BOOST_BIND(&XServer::ServerRoutine,this,_1);
(3)绑定类的成员变量,这个在排序的时候比较有用
有个类如下. 记录人的信息:
class Personal_info {
string name_;
int age_;
public:
int get_age();
string name();
};
vector<Personal_info> vec;
...
现在要对 vec 排序. 可以用 bind 函数做一个比较谓词
std::sort(
vec.begin(),
vec.end(),
boost::bind(
std::less<int>(),
boost::bind(&personal_info::age,_1), //_1 占位符是 sort 中调用比较函数时的第一个参数.
boost::bind(&personal_info::age,_2))); //_2 占位符是 sort 中调用比较函数时的第二个参数.
绑定到map的成员变量:
绑定到成员变量
有:
map<int, string> my_map;
my_map[0]="Boost";my_map[1]="Bind";
现在要输出所有元素的 second 成员. 也就是输出这些字符串. 其中的打印函数如下:
void print_string(const string& s) {
std::cout << s << '/n';
}
则可以:
for_each(
my_map.begin(),
my_map.end(),
boost::bind(
&print_string,
boost::bind(&std::map<int,std::string>::value_type::second,_1)
)
);
(4)函数组合
假如有:
vector<int> ints;
...
想用 std::count_if() 来求ints中有多少是 >5 且 <=10 的. 这在常规代码中通常就要写一个函数来实现这个谓词:
if (i>5 && i<=10) ...
现在用bind则可以:
std::count_if(
ints.begin(), ints.end(),
boost::bind(
std::logical_and<bool>(),
boost::bind(std::greater<int>(),_1,5),
boost::bind(std::less_equal<int>(),_1,10)));
(5)绑定引用和指针
有函数:
void f(int & x) { ++x; }
然后:
int n = 0;
bind(&f, n)(); //我们希望 n==1 . 但实际上没有这样...
要避免这种对象复制. 而 要bind得到的函数对象保存实参的引用语义. 可以:
使用 boost::ref () 或 boost::cref () 如
bind(&f, ref(n) )(); //OK, 执行后 n==1
如果是绑定一个对象到它的成员函数上. 如:
A a;
bind(&A::fun, a ); //则保存的是 a对象的拷贝.
要避免这种拷贝. 除了上面提到的 ref() 外, 也可以:
bind(&A::fun, &a ); //用指针. 反正用对象和用指针都可以. 而用指针可以避免对象拷贝的问题.
(6)绑定函数:
bind () 的第一个参数——被绑定函数——是不被求值的. 如下例:
typedef void (*pf)(int);
std::vector<pf> v; //v中有一些函数指针.
std::for_each(v.begin(), v.end(), bind(_1, 5) ); //想实现 _1(5); 这样的调用. 但这样不行!
正确的做法是借助 boost::apply 模板(来自boost/bind/apply.hpp).
apply也是一个函数对象. 它的作用如下:
apply<void> a; //模板参数为函数对象的返回值类型.
a(x); //相当于调用 x();
a(x, y); //相当于调用 x(y);
a(x, y, z); //相当于调用 x(y, z);
所以错误的bind应该写为:
std::for_each(v.begin(), v.end(), bind(apply<void>(), _1, 5));