本人对模板编程的应用并不是很深,若要用一句话总结我我的对模板编程的理解,我想说的是:模板编程是对类定义的弱化。ios
如何理解“类定义的弱化”?c++
一个完整的类有以下几部分组成:编程
从编译器的角度看,咱们必须明确指定以上3部分,才算完整地定义了一个类而且编译经过。函数
所谓的“类弱化”,是指类的设计者在定义类的时候,并无完整定义一个类,而是把类的其中一部分的定义留给类的使用者。oop
从传统才c++98看,经过模板类,使用者能够参与定义类的部分有:学习
一、成员变量的类型;spa
二、类成员方法参数的类型;设计
//实例代码
template<class T> class Test { public: template<class Param>void TestWork(Param p) { } private: T m_t; };
模板功能大大提升了类设计者代码的可拓展性和可维护性。调试
OK咱们切入主题,C++11可变参数接口在“类弱化”方面有什么提升呢?code
总结地来讲,咱们能够增长一点,使用者能够参与定义类的部分有:
三、类成员方法函数的参数个数。
本总结包含以下两部分:
咱们下面经过一个简单的代码来认识可变参数的“形状”:
template<typename ... Args> void Test(Args ... args) { } int main(int argc, char* argv[]) { Test(1, 2, 3, 4, "abc"); }
以上代码很是简单,咱们在main函数中调用Test函数时,能够传递任意多个参数,且参数的类型也是任意的。若是咱们在VS(VS2010以上版本)下断点调试,咱们能够看到Test函数的参数。其书写形式也很是简单,C++11拓展了模板的书写形式,“typename ... Args”就能够定义一个可变从参数类型。
做为简单的介绍,我以为再也已经没有什么能够在说的了,网上也有不少例子,经典例子就是咱们把传给Test函数的值都打印出来,代码以下:
#include <iostream> template<typename T> void Test(T t) //当参数个数等于1是,进入此函数 { std::cout << t << std::endl; } template<typename T,typename ... Args> void Test(T t, Args ... args) //当参数个数大于1是,进入此函数 { std::cout << t << std::endl; Test(args...); //循环调用Test函数 } int main(int argc, char* argv[]) { Test(1, 2, 3, 4, "abc"); }
下面咱们经过鼠标消息事件分发实例,不使用可变参数列表和使用可变参数列表设计对比两者实现效果的差异。
#include <list> #include <iostream> #include <mutex> #include <algorithm> class IListener //监听者接口类 { public: virtual void OnPress(double dXpos, double dYpos) = 0; virtual void OnCallBack(std::string sParam,int iParam) = 0; }; template<class T> class DispatcherBase { public: std::list<T*>& GetListeners() { return m_listeners; } void AddListener(T* tparam)//一、添加注册listener { auto itor = std::find_if(m_listeners.begin(), m_listeners.end(), find_listener(tparam)); if (itor != m_listeners.end()) return; m_listeners.push_back(tparam); } void RemoveListener(T* tparam) //二、移除注册的listener { auto itor = std::find_if(m_listeners.begin(), m_listeners.end(), find_listener(tparam)); if (itor == m_listeners.end()) return; m_listeners.erase(itor); } protected: std::list<T*> m_listeners; //三、listener的集合 struct find_listener//四、listener查找比较规则定义 { find_listener(T* listener) :m_listener(listener) {} bool operator()(const T* listener) { if (m_listener == listener) return true; else return false; } T* m_listener; }; std::mutex m_mtx; }; class Dispatcher : public DispatcherBase<IListener> //消息分发类 { public: void DispatcherPress(double dXpos, double dYpos) { m_mtx.lock(); auto listners = GetListeners(); for (auto itor : listners) { itor->OnPress(dXpos, dYpos); } m_mtx.unlock(); } void DispatcherCallBack(std::string sParam, int iParam) { m_mtx.lock(); auto listners = GetListeners(); for (auto itor : listners) { itor->OnCallBack(sParam, iParam); } m_mtx.unlock(); } }; class ListenerTest : public IListener //监听者类 { public: ListenerTest(std::string sName) : m_sName(sName) { } virtual void OnPress(double dXpos, double dYpos) { std::cout <<"OnPress:"<< m_sName << std::endl; } virtual void OnCallBack(std::string sParam, int iParam) { std::cout <<"OnCallBack:"<< m_sName << std::endl; } private: std::string m_sName; }; int main() { Dispatcher dispatcher; //消息分发者实例 ListenerTest listener1("listener1"); //消息监听者实例 ListenerTest listener2("listener2"); //消息监听者实例 dispatcher.AddListener(&listener1); dispatcher.AddListener(&listener2); dispatcher.DispatcherCallBack("callbackEvent",1); //执行消息分发动做 dispatcher.DispatcherPress(10, 10); //执行消息分发动做 }
运行结果以下:
上面代码为很是经常使用的观察者模式设计的代码,若是您以为以上代码难懂,直接拷贝到电脑上调试一下会相对容易些。
咱们来总结以上代码的问题点:
void DispatcherPress(double dXpos, double dYpos) { m_mtx.lock(); auto listners = GetListeners(); for (auto itor : listners) { itor->OnPress(dXpos, dYpos); } m_mtx.unlock(); } void DispatcherCallBack(std::string sParam, int iParam)
{ m_mtx.lock(); auto listners = GetListeners(); for (auto itor : listners) { itor->OnCallBack(sParam, iParam); } m_mtx.unlock(); }
下面,咱们就来使用可变参数的方法简化以上的问题:
#pragma once #include <list> #include <functional> #include <algorithm> #include <list> #include <iostream> #include <mutex> #include <algorithm> class IListener { public: virtual void OnPress(double dXpos, double dYpos) = 0; virtual void OnCallBack(std::string sParam,int iParam) = 0; }; template<class T> class Dispatcher { public: template<typename Funtype, typename... Args> void Dispatch(Funtype funtype, Args... args) //可变参数修改后的消息分发事件 { m_mtx.lock(); for (auto &itor : m_listeners) { std::bind(funtype, itor, args...)(); //使用std::bind去绑定具体对象,并调该对象的方法 } m_mtx.unlock(); } void AddListener(T* tparam) { auto itor = std::find_if(m_listeners.begin(), m_listeners.end(), find_listener(tparam)); if (itor != m_listeners.end()) return; m_listeners.push_back(tparam); } void RemoveListener(T* tparam) { auto itor = std::find_if(m_listeners.begin(), m_listeners.end(), find_listener(tparam)); if (itor == m_listeners.end()) return; m_listeners.erase(itor); } protected: std::list<T*> m_listeners; struct find_listener { find_listener(T* listener) :m_listener(listener) {} bool operator()(const T* listener) { if (m_listener == listener) return true; else return false; } T* m_listener; }; std::mutex m_mtx; }; class ListenerTest : public IListener { public: ListenerTest(std::string sName) : m_sName(sName) { } virtual void OnPress(double dXpos, double dYpos) { std::cout << "OnPress:" << m_sName << std::endl; } virtual void OnCallBack(std::string sParam, int iParam) { std::cout << "OnCallBack:" << m_sName << std::endl; } private: std::string m_sName; }; int main() { Dispatcher<IListener> dispatcher; ListenerTest listener1("listener1"); ListenerTest listener2("listener2"); dispatcher.AddListener(&listener1); dispatcher.AddListener(&listener2); dispatcher.Dispatch(&IListener::OnCallBack,"callbackEvent", 1); dispatcher.Dispatch(&IListener::OnPress, 10, 10); }
以上代码运行结果与以前同样,可是咱们发现,不一样的消息分发的时候,咱们都是调用Dispatch函数进行分发,咱们省去了为每一个消息从新定义一个分发事件函数的部分。Dispatch函数的内部实现使用了可变参数的接口设计方法。
咱们从简单的C++可变参数使用,到实际使用示例讲解,了解到了C++11可变参数在模板编程方面应用的效果是很是棒的。
涉及知识点总结:
到此,咱们的文章到此结束,感谢你们的学习,更多优秀设计请持续关注个人博客。