bind的奥秘

作用:1、Bind 是已有的标准库函数bind1stbind2nd的泛化;

           2、减少了对函数指针和类成员指针使用适配器的需要,即不需要再使用ptr_fun和mem_fun_ref

            【使用绑定的语法是一致的,不论是用于值语义或是指针语义,甚至是用于智能指针】

         3、  对compose1compose2,select1stselect2nd函数的扩充

优点:采用统一的语法来创建函数对象

            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表达式时,它将被复制,除非我们显式地告诉

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,行为都不会有变化

绑定到变量,代替select1st,select2nd

需要创建一个绑定器,它把每个元素(类型为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)));

不要过度使用

如果你需要创建一个你都很难弄明白的嵌套bind,有可能就是你已经过度使用了

例如:

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));










你可能感兴趣的:(bind的奥秘)