C++实现委托机制(二)
1.引言:
上一篇文章已经介绍了如何构建一个无参数无返回值的函数指针的委托,这篇文章将对上一文章所述委托进行扩展,使得可以注册任意函数指针,不过再讲篇内容之前先要介绍一下实现这个功能所需要了解的C++11的一个新特性———可变参数模板。
2.可变参数模板:
template(模板)是源于将类型和实现(算法)分离开的思想,为了让写好的算法适用于更多类型使得出现了模板,模板使得参数类别任意化,如果再加上“参数个数的任意化”,那么在参数方面的设计手段就基本上齐备了,有了variadic
template
显然可以让设计出来的函数或是类有更大的复用性。因为有很多处理都是与“处理对象的个数”关系不大的,比如说打屏(printf),比如说比较大小(max,min),比如函数绑定子(bind,function要对应各种可能的函数就要能“任意”参数个数和类型)。如果不能对应任意个参数,那么就总会有人无法重用已有的实现,而不得不再重复地写一个自己需要的处理,而共通库的实现者为了尽可能地让自己写的类(函数)能复用在更多的场景,也不得不重复地写很多的代码或是用诡异的技巧,宏之类的去实现有限个“任意参数”的对应。
所以在C++11中引入了这个新语法,下面我们先看一个例子,了解基本的语法:
- template<typename ... Params> class MyClass;
- MyClass<int, string> a;
在上面这个例子我们可以看到,在定义和申明中用
typename...
表示一个参数包,这样我们使用的时候,传入一个<int,string>那么int,string就会被打包入Params中。恩,你可以吧这个参数包看做一个参数的结构体,并且这个结构体的大小是动态的,并且是匿名的。恩,也就是说你无法使用Params[0]这样的语法去随机调用某个类型。听到这里,觉得是匿名的那应该怎么使用呢?答案是递归展开!!!我们先来看一个函数的例子,假如我想写一个Max函数求传入所有参数的最大值,这个参数支持(int,double,float),返回值为double.那么函数原型你觉得大概可能是这样子的:
- template<typename ...Params>
- double Max(Params... _params)
- {
- double Maxnum;
- //求解过程
- return Maxnum;
- }
但是这样写你会发现你无法获取到任何传入参数的类型和值。恩,所以我们来看下如何使用递归来获得每个参数的类型和值。
- template<typename Head,typename ...Tail>
- double Max(Head first,Tail... rest)
- {
- double Maxnum;
- Maxnum = Max(rest...);
- if (Maxnum < first)
- Maxnum = first;
- return Maxnum;
- }
可以看到,我将函数参数分离了一个出来作为Head,这样我就可以每次处理一个变量,使用递归下降,每次递归减少一个参数。注意:上面的rest...表示参数展开,也就是说将这个参数包展开然后当做参数传进去。但是这样做还是不够的,大家都知道递归需要一个出口。所以说我们需要一个重载版本(因为模板函数不能偏特化)。
- template<typename Head>
- double Max(Head first)
- {
- return first;
- }
这样就有了一个递归出口了。好,我们结合以上的代码写成一个完整的程序,看下如何使用的:
- #include<iostream>
- using namespace std;
- template<typename Head, typename ...Tail>
- double Max(Head first, Tail... rest)
- {
- double Maxnum=0;
- Maxnum = Max(rest...);
- if (Maxnum < first)
- Maxnum = first;
- return Maxnum;
- }
- template<typename Head>
- double Max(Head first)
- {
- return first;
- }
- int main()
- {
- cout << Max(1, 3, 3.4, 5.1, 1.5);
- }
输出结果是: 5.1,同样的,模板类是通过私有继承来实现递归的。
- template<typename Head, typename... Tail>
- class tuple<Head, Tail...> : private tuple<Tail...>{
- Head head;
- public:
- /* implementation */
- };
- template<typename Head>
- class tuple<Head> {
- /* one-tuple implementation */
- };
3.任意参数个数、返回值任意的函数指针委托:
同样的,我们还是先对接口进行修改,因为函数指针再不是void(*)(void)所以,接口也需要是一个模板类,而且还需要是一个可变参数模板。
- template<typename ReturnType, typename ...ParamType>
- class IDelegate
- {
- public:
- IDelegate(){}
- virtual ~IDelegate(){}
- virtual bool isType(const std::type_info& _type) = 0;
- virtual ReturnType invoke(ParamType ... params) = 0;
- virtual bool compare(IDelegate<ReturnType, ParamType...> *_delegate) const = 0;
- };
这样,这个接口的invoke函数将会是根据你的函数类型来动态生成对应的模板了。
同样的,我们把剩下三个类按照如此进行改造:
- //StaticDelegate 普通函数的委托
- template<typename ReturnType, typename ...ParamType>
- class CStaticDelegate :
- public IDelegate<ReturnType, ParamType...>
- {
- public:
- typedef ReturnType(*Func)(ParamType...);
- CStaticDelegate(Func _func) : mFunc(_func) { }
- virtual bool isType(const std::type_info& _type) { return typeid(CStaticDelegate<ReturnType, ParamType...>) == _type; }
- virtual ReturnType invoke(ParamType ... params) { return mFunc(params...); }
- virtual bool compare(IDelegate<ReturnType, ParamType ...> *_delegate)const
- {
- if (0 == _delegate || !_delegate->isType(typeid(CStaticDelegate<ReturnType, ParamType ...>))) return false;
- CStaticDelegate<ReturnType, ParamType ...> * cast = static_cast<CStaticDelegate<ReturnType, ParamType ...>*>(_delegate);
- return cast->mFunc == mFunc;
- }
- virtual ~CStaticDelegate(){}
- private:
- Func mFunc;
- };
- //成员函数委托
- template<typename T, typename ReturnType, typename ...ParamType>
- class CMethodDelegate :
- public IDelegate<ReturnType, ParamType...>
- {
- public:
- typedef ReturnType(T::*Method)(ParamType...);
- CMethodDelegate(T * _object, Method _method) : mObject(_object), mMethod(_method) { }
- virtual bool isType(const std::type_info& _type) { return typeid(CMethodDelegate<T, ReturnType, ParamType...>) == _type; }
- virtual ReturnType invoke(ParamType...params)
- {
- (mObject->*mMethod)(params...);
- }
- virtual bool compare(IDelegate<ReturnType, ParamType...> *_delegate) const
- {
- if (0 == _delegate || !_delegate->isType(typeid(CMethodDelegate<ReturnType, ParamType...>))) return false;
- CMethodDelegate<ReturnType, ParamType...>* cast = static_cast<CMethodDelegate<ReturnType, ParamType...>*>(_delegate);
- return cast->mObject == mObject && cast->mMethod == mMethod;
- }
- CMethodDelegate(){}
- virtual ~CMethodDelegate(){}
- private:
- T * mObject;
- Method mMethod;
- };
- //多播委托
- template<typename ReturnType, typename ...ParamType>
- class CMultiDelegate
- {
- public:
- typedef std::list<IDelegate<ReturnType, ParamType...>*> ListDelegate;
- typedef typename ListDelegate::iterator ListDelegateIterator;
- typedef typename ListDelegate::const_iterator ConstListDelegateIterator;
- CMultiDelegate() { }
- ~CMultiDelegate() { clear(); }
- bool empty() const
- {
- for (ConstListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
- {
- if (*iter) return false;
- }
- return true;
- }
- void clear()
- {
- for (ListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
- {
- if (*iter)
- {
- delete (*iter);
- (*iter) = nullptr;
- }
- }
- }
- CMultiDelegate<ReturnType, ParamType...>& operator+=(IDelegate<ReturnType, ParamType...>* _delegate)
- {
- for (ListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
- {
- if ((*iter) && (*iter)->compare(_delegate))
- {
- delete _delegate;
- return *this;
- }
- }
- mListDelegates.push_back(_delegate);
- return *this;
- }
- CMultiDelegate<ReturnType, ParamType...>& operator-=(IDelegate<ReturnType, ParamType...>* _delegate)
- {
- for (ListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
- {
- if ((*iter) && (*iter)->compare(_delegate))
- {
- if ((*iter) != _delegate) delete (*iter); //避免同一个地址被delete两次
- (*iter) = 0;
- break;
- }
- }
- delete _delegate;
- return *this;
- }
- std::vector<ReturnType> operator()(ParamType... params)
- {
- ListDelegateIterator iter = mListDelegates.begin();
- std::vector<ReturnType> _Results;
- while (iter != mListDelegates.end())
- {
- if (0 == (*iter))
- {
- iter = mListDelegates.erase(iter);
- }
- else
- {
- _Results.push_back((*iter)->invoke(params...));
- ++iter;
- }
- }
- return _Results;
- }
- private:
- CMultiDelegate<ReturnType, ParamType...>(const CMultiDelegate& _event);
- CMultiDelegate<ReturnType, ParamType...>& operator=(const CMultiDelegate& _event);
- private:
- ListDelegate mListDelegates;
- };
但是这样写你会发现你在newDelegate里面对于传来的函数指针进行new
CStaticDelegate或者new
CMethodDelegate的时候需要制定函数返回值、参数的个数和类型,这显然不满足动态类型演化。这时候我们想,能不能给定一个函数指针,让代码自动去识别这个函数的返回值和参数呢?答案是可以的,我们只需要对上面的CStaticDelegate和CMethodDelegate特化一个版本即可。
这里使用了一个小技巧:通过函数指针去得到函数返回值、参数个数类型。详情可以看看这里:http://bbs.csdn.net/topics/390652170?page=1
这里我就直接贴我写好的代码:
- //普通函数的委托特化版本
- template<typename ReturnType, typename ...ParamType>
- class CStaticDelegate<ReturnType(*)(ParamType ...)> :
- public IDelegate<ReturnType, ParamType ...>
- {
- public:
- //定义 Func 为 void (void) 函数类型指针。
- typedef ReturnType(*Func)(ParamType...);
- CStaticDelegate(Func _func) : mFunc(_func) { }
- virtual bool isType(const std::type_info& _type) { return typeid(CStaticDelegate<ReturnType(*)(ParamType ...)>) == _type; }
- virtual ReturnType invoke(ParamType ... params) { return mFunc(params...); }
- virtual bool compare(IDelegate<ReturnType, ParamType ...> *_delegate)const
- {
- if (0 == _delegate || !_delegate->isType(typeid(CStaticDelegate<ReturnType(*)(ParamType ...)>))) return false;
- CStaticDelegate<ReturnType(*)(ParamType ...)> * cast = static_cast<CStaticDelegate<ReturnType(*)(ParamType ...)>*>(_delegate);
- return cast->mFunc == mFunc;
- }
- virtual ~CStaticDelegate(){}
- private:
- Func mFunc;
- };
- //成员函数委托特化
- template<typename T, typename ReturnType, typename ...ParamType>
- class CMethodDelegate<T,ReturnType (T:: *)(ParamType...)> :
- public IDelegate<ReturnType, ParamType...>
- {
- public:
- typedef ReturnType(T::*Method)(ParamType...);
- CMethodDelegate(T * _object, Method _method) : mObject(_object), mMethod(_method) { }
- virtual bool isType(const std::type_info& _type) { return typeid(CMethodDelegate<T,ReturnType(T:: *)(ParamType...)>) == _type; }
- virtual ReturnType invoke(ParamType...params)
- {
- return (mObject->*mMethod)(params...);
- }
- virtual bool compare(IDelegate<ReturnType, ParamType...> *_delegate) const
- {
- if (0 == _delegate || !_delegate->isType(typeid(CMethodDelegate<T, ReturnType(T:: *)(ParamType...)>))) return false;
- CMethodDelegate<T, ReturnType(T:: *)(ParamType...)>* cast = static_cast<CMethodDelegate<T, ReturnType(T:: *)(ParamType...)>*>(_delegate);
- return cast->mObject == mObject && cast->mMethod == mMethod;
- }
- CMethodDelegate(){}
- virtual ~CMethodDelegate(){}
- private:
- T * mObject;
- Method mMethod;
- };
这样我生成的时候只需要new CStaticDelegate<decltype(Func)>(Func),而特化版本的可以自动识别这个Func的返回值、参数个数和类型。
最后我给出newDelegate的代码:
- template< typename T>
- CStaticDelegate<T>* newDelegate(T func)
- {
- return new CStaticDelegate<T>(func);
- }
- template< typename T,typename F>
- CMethodDelegate<T,F>* newDelegate(T * _object, F func)
- {
- return new CMethodDelegate<T, F>(_object, func);
- }
写到这里基本上可变参数的委托就完成了,不过还需要注意一点就是void无返回值类型多播委托需要特殊处理。所以我们还需要一个多播委托对于ReturnType为void这个情况的特化。
- template< typename ...ParamType>
- class CMultiDelegate<void, ParamType...>
- {
- public:
- typedef std::list<IDelegate<void, ParamType...>*> ListDelegate;
- typedef typename ListDelegate::iterator ListDelegateIterator;
- typedef typename ListDelegate::const_iterator ConstListDelegateIterator;
- CMultiDelegate() { }
- ~CMultiDelegate() { clear(); }
- bool empty() const
- {
- for (ConstListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
- {
- if (*iter) return false;
- }
- return true;
- }
- void clear()
- {
- for (ListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
- {
- if (*iter)
- {
- delete (*iter);
- (*iter) = nullptr;
- }
- }
- }
- CMultiDelegate<void, ParamType...>& operator+=(IDelegate<void, ParamType...>* _delegate)
- {
- for (ListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
- {
- if ((*iter) && (*iter)->compare(_delegate))
- {
- delete _delegate;
- return *this;
- }
- }
- mListDelegates.push_back(_delegate);
- return *this;
- }
- CMultiDelegate<void, ParamType...>& operator-=(IDelegate<void, ParamType...>* _delegate)
- {
- for (ListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
- {
- if ((*iter) && (*iter)->compare(_delegate))
- {
- if ((*iter) != _delegate) delete (*iter); //避免同一个地址被delete两次
- (*iter) = 0;
- break;
- }
- }
- delete _delegate;
- return *this;
- }
- void operator()(ParamType... params)
- {
- ListDelegateIterator iter = mListDelegates.begin();
- while (iter != mListDelegates.end())
- {
- if (0 == (*iter))
- {
- iter = mListDelegates.erase(iter);
- }
- else
- {
- (*iter)->invoke(params...);
- ++iter;
- }
- }
- }
- private:
- CMultiDelegate<void, ParamType...>(const CMultiDelegate& _event);
- CMultiDelegate<void, ParamType...>& operator=(const CMultiDelegate& _event);
- private:
- ListDelegate mListDelegates;
- };
所有代码都已经贴出来了,我把这些模板全部放到了MyDelegate.h头文件中。下面给一个使用的例子:
- #include "MyDelegate.h"
- using namespace Delegate;
- void NormalFunc(int a)
- {
- printf("这里是普通函数 :%d\n", a);
- }
- class A
- {
- public:
- static void StaticFunc(int a)
- {
- printf("这里是成员静态函数 : %d\n", a);
- }
- void MemberFunc(int a)
- {
- printf("这里是成员非静态函数 : %d\n", a);
- }
- };
- int _tmain(int argc, _TCHAR* argv[])
- {
- //首先创建了一个返回值为 void ,参数为int 的一个委托。
- CMultiDelegate<void, int> e;
- //将三个函数注册到该委托中
- e += newDelegate(NormalFunc);
- e += newDelegate(A::StaticFunc);
- e += newDelegate(&A(), &A::MemberFunc);
- //调用
- e(1);
- return 0;
- } <strong> </strong>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
2013-03-20 float compare 0