巧妙使用std::mem_fun

例如:假设有如下的代码:
class Employee
{
public:
 int DoSomething(){/*...*/}
}

std::vector Emps;

假设我们要调用Emps里面所包含的所有Employee的DoSomething();一般初学者会这样调用:
for (std::vector::iteror it=Emps.begin(); it!=Emps.Ends(); it++)
{
 (*it).DoSomething();
}

而定义一个全局的仿函数,使用STL中的for_each的用法也是司空见惯的,如:
int GiveDoSomething(Employee& e)
{
 return e.DoSomething();
}
std::for_each(emps.begin(),emps.end(),&GiveDoSomething);

但是这种访问方式需要单独定义一个全局的仿函数GiveDoSomething.而有没有办法直接调用Employee中对应的成员函数的话?答案是这样子:
std::vector emps;

std::for_each(emps.begin(),emps.end(),std::mem_fun_ref(&Employee::DoSomething));

而倘若容器中包含的是指向对象的指针,你就应该使用mem_fun:
std::vector emp_ptrs;

std::for_each(emp_ptrs.begin(),emp_ptrs.end(),std::mem_fun(&Employee::DoSomething));

不过有一点要注意,请看DoSomething函数是无参的,而对于有一个参数的函数,可以使用std::bind...辅助函数,使用原则和mem_fun一样。然而遗憾的是,这种做法不适应那些接受两个或多个参数的函数,但是这并不代表mem_fun一无用处。

但是mem_fun这些特质同样会带给我们一些尴尬的事情,例:
std::mem_fun(&(std::vector::clear))

std::vector::clear()的函数参数是无参的,返回void.这样调用会成功吗?

C++标准里面关于标准库的部分在描述某些成员函数的实现时故意留了一些余地。尤其是下面这两句话:
1.一个具有默认参数的成员函数签名可以被“两个或多个具有等价行为的成员函数签名”所替代
2.成员函数签名可以具有额外的默认参数
上面的第二句话就是问题所在,即那些可有可无,若隐若现的额外参数就是肇事者,Herb Sutter称之为(peekaboo(一种类似捉迷藏的游戏)参数).

大多数时候,那些由实现定认的额外的默认peekaboo参数根本不会引起人们的注意。例如,当你调用一个成员函数的时候,那些peekaboo参数会绑定到它们的默认值,因而平常你根本不用去关心标准库是否为这些函数添加了一些额外的形参。这样的话,当你不得不知道某个成员函数的确切签名时,这些可能的额外形参就成了大问题!假设你使用了mem_fun的时候。注意,即便你的编译器能够正确地推导出模板实参也无济于事,这是因为两个潜在问题:

1.如果有问题的成员函数实际上具有一个带默认值的形参,而你又不期望出现这个形参的话,你就使用像std::bind2nd这样的设施对付它。但是你这样做了之后,你的代码移植到另一个平台上,而该平台上的标准库中相应的成员函数却具有一个不同类型的额外形参,或者根本没有额外的形参,那么你的代码同样无法工作。就是说,你的代码本来就是不可移植的.
2.如果有问题的成员函数实现上具有两个或多个形参,就根本无法将mem_fun用在自身上。

还有一个最基本的问题:mem_fun里面毕竟是要带入一个函数指针,我们不可能可移植地创建一个指向标准库里的成员函数的指针。


切记:mem_fun可以可移植地复用到你的任何代码中,只要你愿意,但是它却不能可移植地复用到标准库自身。
 

你可能感兴趣的:(巧妙使用std::mem_fun)