Boost源码剖析:C++泛型函数指针类
序幕
如你所知,Boost库是一个功能齐全、具有行业实力的库,众多C++权威的加入使其达到了巅峰。尤其是泛型的强大威力在其中发挥的淋漓尽致,令人瞠目结舌。
不过弱水三千,我们只拿一瓢饮料。下面,我试着从最简单的世界开始,一步一步带领你走进源代码的世界,探索boost::function(以下简称function)内部的微妙结构。
通常,在简单的情况下,对函数的调用简单而直观,就像这样:
int fun(int some val);
int main(){
fun(10);
}
但是,您可能需要在某个时候保存函数指针,并在以后的另一个时间调用它,如下所示:
int fun(int);
typedef int(* func _ handle)(int);
int main(){
func _ handle FH = fun;
...//做点什么
FH(10);
}
但是,如果乐趣的形式是void fun(int)呢?如你所见,乐趣可能有无数种形式。如果每种形式的乐趣都有一个对应的funC _ handle是typedef,程序员会不知所措,代码可能会变得臃肿难看。就算好玩是模仿功能?
幸运的是,C++泛型可以使代码变得优雅和精炼。面对无数的可能性,泛型是选择。因此,您只需要一个可以保存函数指针的通用模板类(对应于命令模式)。因为泛型编程有一个先天的优势——它可以在编译器的帮助下,根据用户提供的类型信息,在编译时被具体化(物化),所以一个泛型类可以有无限个实例化,也就是说,它可以容纳无限个可能类型的函数或类似函数的东西(如模仿函数)。这个类(Boost库中的类名是function)相对于函数指针应该有以下优点:
同一功能对象应能接受与其形式兼容的所有功能和模仿功能,如:
int f1(int);//这是一个函数,形式为int(int)
short F2(double);//这个函数的形式是short(double)
Struct functor //这是一个模仿函数类,形式为int(int)
{
int operator()(int){ }
};
函子F3;//创建一个模仿函数对象
boost::function < int(int)> func;// int(int)类型函数或仿函数
func = f1;//接受f1
func(10);//调用f1(10)
func = F2;//也可以接受短(双)型F2
func(10);//调用F2(10)
func = F3;//也可以接受仿函数F3
func(10);//调用f3(10)
该函数应该能够使用参数绑定和其他函数构造库。比如function也要能接受std::bind1st返回的模仿函数。这一点其实第一点就保证了。
当调用空的接受对象时,该函数应该具有可预测的行为。
显然,第一点是我们的重点。所谓形式上的兼容性,即对于:
R1 (T0,T1,T2,...,TN) = >函数类型1
R2 (P0,P1,P2,...,PN) = >函数类型2
两类功能(广义)只要:
1.R2可以含蓄地转化为R1。
2.所有Ti都可以隐式地转换成Pi (i取0,1,2,...)
也就是说boost:: function < function type 1 >可以接受FunctionType2的函数(注意反过来是不行的)。支持这个断言的理由是,只要Ti可以隐式转换为Pi,参数转发给实函数调用就是安全的,如果R2可以隐式转换为R1,返回实函数调用返回的值就是安全的。这里安全的意思是C++类型系统认为隐式转换不会丢失信息,或者会给出编译警告,但是可以编译。
后面会看到,boost::函数通过所谓的invoker非常巧妙地实现了这一点,并防止了形式不兼容的函数赋值。
位律师回复
0条评论