std::tr1::function源码剖析(一)
std::tr1::function源码剖析(二)
虽然当时仔细的研究了MS的STL库里function和bind的代码,但是还有不甚明白的地方。刚好昨天有时间,就想彻底的弄明白function到底是怎么回事。没想到这一下子还真的想通了!
function类在功能上是实现了C#的委托,所谓委托,就是一种数据结构,它引用静态方法或者引用类实例的实例方法。通俗地说,委托是指向方法的引用(或指针)。
我们知道C、C++可以很容易的将一个全局函数绑定到一个变量上,如:
int Add (int a,int b) {return a+b; }
typedef int(*pAddFunc)(int,int);
int main ()
{
pAddFunc add = &Add;
cout<<(*add)(3,4)< return 0; } 在上面的例子里,我们定义了一个函数指针类型pAddFunc,它可以绑定一个int(int,int)类型的函数,然后在使用的时候我们可以通过该类型的指针引用函数。 然而如何能将一个类成员函数绑定到一个函数指针上呢?而我们知道类的成员函数在调用的时候必须引用某个实例,如: class Add { public: int add(int a,int b) {return a+b; } }; int main() { typedef int(Add::*pMemFunc)(int,int); pMemFunc add = &Add::add; Add a; cout<<(a.*add)(3,4)< return 0; } 也就是说在实现上类成员函数指针比普通函数指针多了一个类实例的引用(或者指针)。那么我们有什么办法可以将类成员函数指针和普通函数指针实现在一个类里面呢?需要提醒一下了,这里有一个陷阱,如果你想只需要一个类就可以完成上述工作,那你就掉进去了。我当初就是这么想的,然后怎么也得不到答案。但是昨天突然间开了窍,原来还需要一点点设计原则——里氏代换原则在里面。 为了说明白问题的来龙去脉,我会一步一步的解释。首先我们写一个普通函数的委托类,如: template<typename _ReturnType,typename _T1,typename _T2> class FunctionOfPtr { typedef _ReturnType(*PtrFuncType)(_T1, _T2); public: PtrFuncType m_pfunc; FunctionOfPtr(PtrFuncType pf) { m_pfunc = pf; } virtual PtrFuncType GetFunc() { return m_pfunc; } virtual _ReturnType operator()(_T1 arg1, _T2 arg2) { return (*m_pfunc)(arg1, arg2); } }; template<typename _ReturnType,typename _T1,typename _T2> FunctionOfPtr<_ReturnType, _T1, _T2> bind(_ReturnType(*pFunc)(_T1, _T2)) { return FunctionOfPtr<_ReturnType, _T1, _T2>(pFunc); } 这样我们就可以很方便的将普通函数委托给FunctionOfPtr对象了,为了方便还实现了一个简单的bind函数。这样我们在使用普通函数的时候就可以这样用了,如: int add(int a,int b){return a+b; } int main() { FunctionOfPtr<int,int,int> f = bind(&add); cout< return 0; } 接下来我们需要实现一个类的成员函数的委托类,如: template<typename _ReturnType,typename _Class,typename _T1,typename _T2> class FunctionOfMem { typedef _ReturnType(*PtrFuncType)(_T1, _T2); typedef _ReturnType(_Class::*MemFuncType)(_T1, _T2); public: MemFuncType m_pfunc; _Class* m_obj; FunctionOfMem(MemFuncType func, _Class* obj) { m_pfunc = func; m_obj = obj; } virtual PtrFuncType GetFunc() { return (PtrFuncType)(*(long*)&m_pfunc); } virtual _ReturnType operator()(_T1 arg1, _T2 arg2) { return (m_obj->*m_pfunc)(arg1, arg2); } }; template<typename _ReturnType,typename _Class,typename _T1,typename _T2> FunctionOfMem<_ReturnType, _Class, _T1, _T2> bind(_ReturnType(_Class::*pMemFunc)(_T1, _T2), _Class* obj) { return FunctionOfMem<_ReturnType, _Class, _T1, _T2>(pMemFunc, obj); } 这样我们就可以很方便的将类的成员函数委托给FunctionOfMem对象了,为了方便也实现了一个简单的bind函数。这样我们在使用类成员函数的时候局可以这样用了,如: class Add { public: int add(int a,int b) {return a+b; } }; int main() { Add a; FunctionOfMem<int,Add,int,int> f = bind(&Add::add, &a); cout< return 0; } 这样我们就分别完成了普通函数和类的成员函数的委托。可是这样的话,普通函数和类的成员函数在定义的时候就不统一了。而STL里面的function是可以实现的。 诶!你再仔细瞅瞅FunctionOfPtr和FunctionOfMem的定义,发现了什么? template<typename _ReturnType,typename _T1,typename _T2> class FunctionOfPtr; template<typename _ReturnType,typename _Class,typename _T1,typename _T2> class FunctionOfMem; 是的,我发现了。它们在定义的时候只差一个typename _Class,而且它们的内部函数也有很多相同的地方!那么我可能需要一个基类来代替这两个子类了。说干就干,如: template<typename _ReturnType,typename _T1,typename _T2> class FunctionBase { public: typedef _ReturnType(*PtrFuncType)(_T1, _T2); virtual PtrFuncType GetFunc() = 0; virtual _ReturnType operator()(_T1 arg1, _T2 arg2) = 0; }; template<typename _ReturnType,typename _Class,typename _T1,typename _T2> class FunctionOfMem : public FunctionBase<_ReturnType, _T1, _T2> { public: typedef _ReturnType(_Class::*MemFuncType)(_T1, _T2); MemFuncType m_pfunc; _Class* m_obj; FunctionOfMem(MemFuncType func, _Class* obj) { m_pfunc = func; m_obj = obj; } virtual PtrFuncType GetFunc() { return (PtrFuncType)(*(long*)&m_pfunc); } virtual _ReturnType operator()(_T1 arg1, _T2 arg2) { return (m_obj->*m_pfunc)(arg1, arg2); } }; template<typename _ReturnType,typename _T1,typename _T2> class FunctionOfPtr : public FunctionBase<_ReturnType, _T1, _T2> { public: PtrFuncType m_pfunc; FunctionOfPtr(PtrFuncType pf) { m_pfunc = pf; } virtual PtrFuncType GetFunc() { return m_pfunc; } virtual _ReturnType operator()(_T1 arg1, _T2 arg2) { return (*m_pfunc)(arg1, arg2); } }; template<typename _ReturnType,typename _T1,typename _T2> class Functor { public: FunctionBase<_ReturnType, _T1, _T2>* m_pfunc; Functor() : m_pfunc(NULL) {} ~Functor() { if (m_pfunc != NULL) { delete m_pfunc; m_pfunc = NULL; } } template<typename _Class> Functor(_ReturnType(_Class::*pMemFunc)(_T1, _T2), _Class* obj) { m_pfunc = new FunctionOfMem<_ReturnType, _Class, _T1, _T2>(pMemFunc, obj); } Functor(_ReturnType(*pPtrFunc)(_T1, _T2)) { m_pfunc = new FunctionOfPtr<_ReturnType, _T1, _T2>(pPtrFunc); } _ReturnType operator()(_T1 arg1, _T2 arg2) { return (*m_pfunc)(arg1, arg2); } Functor& operator=(Functor& f) { m_pfunc = f.m_pfunc; f.m_pfunc = NULL; return *this; } }; template<typename _ReturnType,typename _Class,typename _T1,typename _T2> Functor<_ReturnType, _T1, _T2> bind(_ReturnType(_Class::*pMemFunc)(_T1, _T2), _Class* obj) { return Functor<_ReturnType, _T1, _T2>(pMemFunc, obj); } template<typename _ReturnType,typename _T1,typename _T2> Functor<_ReturnType, _T1, _T2> bind(_ReturnType(*pFunc)(_T1, _T2)) { return Functor<_ReturnType, _T1, _T2>(pFunc); } class Add { public: int add(int a,int b) { return a+b; } }; int add(int a,int b) { return a+b; } int main() { Add a; Functor<int,int,int> f; f = bind(&Add::add, &a); cout< f = bind(&add); cout< return 0; } 重新设计后的FunctionOfMem和FunctionOfPtr都可以委托给Functor类,这样客户端在使用Functor对象的时候就可以不需要知道到底是调用的普通函数还是类成员函数了。 但是我们的Functor虽然在设计上没有问题了,但是和STL库里面的function还是有点不一样,为什么呢?因为STL库里面的function通过宏定义实现了不同参数(0…10)形式的function。我这里还有一个是用宏定义之后的版本,但是读过之后就会发现,那不是给人读的。 #define _COMMA0 , #define _MCOMMA , #define YNAME(x, y) x##y #define FIRST(x) YNAME(x, 0) #define _CDR(x) YNAME(x, 1) #define LIST(x) FIRST(x) _MCOMMA _CDR(x) #define FIRST2(x, y) YNAME(x, 0) YNAME(y, 0) #define _CDR2(x, y) YNAME(x, 1) YNAME(y, 1) #define LIST2(x, y) FIRST2(x, y) _MCOMMA _CDR2(x, y) #define _CLASS_ARG0 LIST(typename Arg) #define _CLASS_NO_ARG0 LIST(Arg) #define _CLASS_WITH_ARG0 LIST2(Arg, arg) #define _C_CLASS_ARG0 _COMMA0 _CLASS_ARG0 // typename Arg0, typename Arg1... #define _C_CLASS_NO_ARG0 _CLASS_NO_ARG0 // Arg0, Arg1... #define _C_CLASS_WITH_ARG0 _CLASS_WITH_ARG0 // Arg0 arg0, Arg1 arg1... template class FunctionBase { public: typedef _ReturnType(*PtrFuncType)(_C_CLASS_NO_ARG0); virtual PtrFuncType GetFunc() = 0; virtual _ReturnType operator()(_C_CLASS_WITH_ARG0) = 0; }; template class FunctionOfMem : public FunctionBase<_ReturnType, _C_CLASS_NO_ARG0> { public: typedef _ReturnType(_Class::*MemFuncType)(_C_CLASS_NO_ARG0); MemFuncType m_pfunc; _Class* m_obj; FunctionOfMem(MemFuncType func, _Class* obj) { m_pfunc = func; m_obj = obj; } virtual PtrFuncType GetFunc() { return (PtrFuncType)(*(long*)&m_pfunc); } virtual _ReturnType operator()(_C_CLASS_WITH_ARG0) { return (m_obj->*m_pfunc)(arg0, arg1); } }; template class FunctionOfPtr : public FunctionBase<_ReturnType, _C_CLASS_NO_ARG0> { public: PtrFuncType m_pfunc; FunctionOfPtr(PtrFuncType pf) { m_pfunc = pf; } virtual PtrFuncType GetFunc() { return m_pfunc; } virtual _ReturnType operator()(_C_CLASS_WITH_ARG0) { return (*m_pfunc)(arg0, arg1); } }; template class Functor { public: FunctionBase<_ReturnType, _C_CLASS_NO_ARG0>* m_pfunc; Functor() : m_pfunc(NULL) {} ~Functor() { if (m_pfunc != NULL) { delete m_pfunc; m_pfunc = NULL; } } template Functor(_ReturnType(_Class::*pMemFunc)(_C_CLASS_NO_ARG0), _Class* obj) { m_pfunc = new FunctionOfMem<_ReturnType, _Class, _C_CLASS_NO_ARG0>(pMemFunc, obj); } Functor(_ReturnType(*pPtrFunc)(_C_CLASS_NO_ARG0)) { m_pfunc = new FunctionOfPtr<_ReturnType, _C_CLASS_NO_ARG0>(pPtrFunc); } _ReturnType operator()(_C_CLASS_WITH_ARG0) { return (*m_pfunc)(arg0, arg1); } Functor& operator=(Functor& f) { m_pfunc = f.m_pfunc; f.m_pfunc = NULL; return *this; } }; template Functor<_ReturnType, _C_CLASS_NO_ARG0> bind(_ReturnType(_Class::*pMemFunc)(_C_CLASS_NO_ARG0), _Class* obj) { return Functor<_ReturnType, _C_CLASS_NO_ARG0>(pMemFunc, obj); } template Functor<_ReturnType, _C_CLASS_NO_ARG0> bind(_ReturnType(*pFunc)(_C_CLASS_NO_ARG0)) { return Functor<_ReturnType, _C_CLASS_NO_ARG0>(pFunc); } class Add { public: int add(int a, int b) { return a+b; } }; int add(int a, int b) { return a+b; }