作用:1、Bind 是已有的标准库函数bind1st和bind2nd的泛化;
2、减少了对函数指针和类成员指针使用适配器的需要,即不需要再使用ptr_fun和mem_fun_ref
【使用绑定的语法是一致的,不论是用于值语义或是指针语义,甚至是用于智能指针】
3、 对compose1和compose2,select1st和select2nd函数的扩充
优点:采用统一的语法来创建函数对象
Boost.Bind 实现支持九个占位符(_1, _2, _3, 等等)
class status {
std::string name_;
bool ok_;
public:
status(conststd::string& name):name_(name),ok_(true) {}
void break_it() {
ok_=false;
}bool is_broken()const {
return ok_;
}
void report() const{
std::cout <<name_ << " is " <<
(ok_ ?"working nominally":"terribly broken") << '\n';
}
};
std::for_each(
statuses.begin(),
statuses.end(),
boost::bind(&status::report,_1));
_1用于替换这个函数所调用的绑定器的第一个实际参数。
std::vector<status*>p_statuses;
p_statuses.push_back(newstatus("status 1"));
p_statuses.push_back(newstatus("status 2"));
p_statuses.push_back(newstatus("status 3"));
p_statuses.push_back(newstatus("status 4"));
p_statuses[1]->break_it();
p_statuses[2]->break_it();
使用bind, 我们就无须关心我们处理的元素是指针了,与容器存放元素的用法一样:
std::for_each(
p_statuses.begin(),
p_statuses.end(),
boost::bind(&status::report,_1));
std::vector<boost::shared_ptr<status>> s_statuses;
s_statuses.push_back(
boost::shared_ptr<status>(newstatus("status 1")));
s_statuses.push_back(
boost::shared_ptr<status>(newstatus("status 2")));
s_statuses.push_back(
boost::shared_ptr<status>(newstatus("status 3")));
s_statuses.push_back(
boost::shared_ptr<status>(newstatus("status 4")));
s_statuses[1]->break_it();
s_statuses[2]->break_it();mem_fun和mem_fun_ref都不适用,因为智能指针没有一个名为report的成员函数,所以以下代码编译失败。
std::for_each(
s_statuses.begin(),
s_statuses.end(),
boost::bind(&status::report,_1));成员变量:
以前:需要编写排序谓词,即函数对象
现在:bind直接绑定,不需要排序谓词
例如:
class personal_info {
std::string name_;
std::string surname_;
unsigned int age_;
public:
personal_info(
const std::string& n,
const std::string& s,
unsigned intage):name_(n),surname_(s),age_(age) {}
std::string name() const {
return name_;
}
std::string surname() const {
return surname_;
}unsigned int age() const {
return age_;
}
};
按照年龄排序:class personal_info_age_less_than :
public std::binary_function<
personal_info,personal_info,bool> {
public:
bool operator()(
const personal_info& p1,constpersonal_info& p2) {
return p1.age()<p2.age();
}
};
以前:std::sort(vec.begin(),vec.end(),personal_info_age_less_than());
现在:boost::bind(
std::less<unsigned int>(),
boost::bind(&personal_info::age,_1),
boost::bind(&personal_info::age,_2));还可以方便的改变排序规则:
例如,按 last name 排序。
std::sort(
vec.begin(),
vec.end(),
boost::bind(
std::less<std::string>(),
boost::bind(&personal_info::surname,_1),
boost::bind(&personal_info::surname,_2)));函数组合,代替compose1,compose2
if (i>5 &&i<=10)
boost::bind(
std::logical_and<bool>(),
boost::bind(std::greater<int>(),_1,5),
boost::bind(std::less_equal<int>(),_1,10));
以前:
STL中compose1:
for_each(v.begin(),v.end(),compose1(
bind2st(multiplies<int>(),3),
bind2st(plus<int>(),2))); //(v+2)*3现在:v*1.1*0.9
写法一:boost::bind(
std::multiplies<double>(),0.90,
boost::bind<double>(
std::multiplies<double>(),_1,1.10)
)或者
写法二:boost::bind<double>(
std::multiplies<double>(),
boost::bind<double>(
std::multiplies<double>(),_1,1.10),0.90)传递某种类型的实例给一个bind表达式时,它将被复制,除非我们显式地告诉
bind不要复制它;
类
class tracer {
public:
tracer() {
std::cout <<"tracer::tracer()\n";
}
tracer(consttracer& other) {
std::cout <<"tracer::tracer(const tracer& other)\n";
}
tracer&operator=(const tracer& other) {
std::cout <<
"tracer&tracer::operator=(const tracer& other)\n";
return *this;
}
~tracer() {
std::cout <<"tracer::~tracer()\n";
}
void print(conststd::string& s) const {
std::cout <<s << '\n';
}
};
tracer t;
boost::bind(&tracer::print,t,_1)
(std::string("I'mcalled on a copy of t\n"));
结果出现拷贝:
tracer::tracer()
tracer::tracer(consttracer& other)
tracer::tracer(consttracer& other)
tracer::tracer(consttracer& other)
tracer::~tracer()
tracer::tracer(consttracer& other)
tracer::~tracer()
tracer::~tracer()
I'm called on acopy of t
tracer::~tracer()
tracer::~tracer()//
译注:原文没有这一行,有误
拷贝的缺点:如果我们使用的对象的拷贝动作代价昂贵
优点:bind表达式以及由它所得到的绑定器不依赖于原始对象(在这里是t)的生存期,这通常正是想要的。
避免拷贝:使用引用或指针
使用引用:boost::ref和boost::cref(分别用于引用和const引用)
tracer t;
boost::bind(&tracer::print,boost::ref(t),_1)(
std::string("I'mcalled directly on t\n"));
Executing the codegives us this:
tracer::tracer()
I'm calleddirectly on t
tracer::~tracer()
bind表达式使用原始的实例,这意味着没有tracer对象的拷贝了。同时,也意味着绑定器现在要依赖于tracer实例的生存期了。
使用指针:
tracer t;
boost::bind(&tracer::print,&t,_1)(
std::string("I'mcalled directly on t\n"));
即把它绑定到最先声明该成员函数为虚拟的基类的那个虚拟函数上。
这个绑定器就可以用于所有的派生类。
class base {
public:
virtual void print() const {
std::cout << "I ambase.\n";
}
virtual ~base() {}
};
class derived : public base {
public:
void print() const {
std::cout << "I amderived.\n";
}
};
derived d;
base b;
boost::bind(&base::print,_1)(b);
boost::bind(&base::print,_1)(d);
运行这段代码可以清楚地看到结果正是我们所希望的。
I am base.
I am derived.
如果你bind了一个成员函数而后来它被一个派生类重新定义了,或者一个虚拟函数在基类中是公有的而在派生类中变成了私有的,那么还可以正常工作吗?
是的,不管你是否使用 Boost.Bind,行为都不会有变化。需要创建一个绑定器,它把每个元素(类型为std::pair)的second成员传给绑定的函数。
void print_string(const std::string& s){
std::cout << s << '\n';
}
std::map<int,std::string> my_map;
my_map[0]="Boost";
my_map[1]="Bind";
std::for_each(
my_map.begin(),
my_map.end(),
boost::bind(&print_string, boost::bind(
&std::map<int,std::string>::value_type::second,_1)));
例如:
void print(std::ostream* os,int i) {
(*os) << i << '\n';
}
int main() {
std::map<std::string,std::vector<int> > m;
m["Strange?"].push_back(1);
m["Strange?"].push_back(2);
m["Strange?"].push_back(3);
m["Weird?"].push_back(4);
m["Weird?"].push_back(5);
std::for_each(m.begin(),m.end(),
boost::bind(&print,&std::cout,
boost::bind(&std::vector<int>::size,
boost::bind(
&std::map<std::string,
std::vector<int>>::value_type::second,_1))));
作用:绑定器对pair(即std::map<std::string,std::vector<int>>::value_type)的成员second调用成员函数size简化:使用函数对象
class print_size {
std::ostream& os_;
typedef std::map<std::string,std::vector<int>> map_type;
public:
print_size(std::ostream& os):os_(os) {}
void operator()(
const map_type::value_type& x) const {
os_ << x.second.size() << '\n';
}
};
现在:
std::for_each(m.begin(),m.end(),print_size(std::cout));