c++ 模板技巧——类型萃取
2026/9/19 11:08:01 网站建设 项目流程
//traits.h /*制定输入 - 输出类型规则*/ template <class T> struct RtnType { typedef T return_type;//默认返回类型和输入类型一致 }; template <class T> struct RtnType<T*> {//特化,当输入的是指针类型,返回类型规定为指针原型 typedef T return_type; }; template <class T> struct RtnType<const T*> {//特化常量指针类型,当输入的是常量指针类型,返回类型规定为原型指针 typedef T* return_type; }; // 你还可以根据需要,特化不同的输入输出规则 /*特性萃取器*/ template <class unknown_class> struct unknown_class_traits { typedef typename unknown_class::return_type return_type; }; ///*特性萃取器 —— 针对指针*/ //template <class unknown_class> //struct unknown_class_traits<unknown_class*> { // typedef unknown_class return_type; //}; // ///*特性萃取器 —— 针对常量指针*/ //template <class unknown_class> //struct unknown_class_traits<const unknown_class*> { // typedef const unknown_class return_type; //}; #define RType typename unknown_class_traits<RtnType<T> >::return_type /*决定使用哪一个类型*/ template <class T> inline RType return_type(T) { return RType(); } /*接口默认实现*/ template <class T> inline RType implement(T param) { cout << "General Version of implement" << endl; return RType(); } template <class T, T Val> struct var_constant { const T value = Val; using value_type = T; using type = var_constant; }; template <bool Val> struct var_constant<bool, Val>//特化bool类型 { const bool value = Val; using value_type = bool; using type = var_constant; }; template<class T1, class T2> struct is_same_type { static const bool value = false; }; template<class T> struct is_same_type<T, T> { static const bool value = true; }; template<class T1, class T2> inline bool compare_type(T1, T2) { var_constant<bool, is_same_type<T1, T2>::value> bConstant; return bConstant.value; };

(注:更完整的类型萃取案例可参考博客"c++ 拆分函数返回值和参数类型_c++ gmock指定函数里的方法-CSDN博客")

//main.cpp #include "traits.h" class A { }; struct B { }; A implement(A) { cout << "use object value type version" << endl; return A(); } B implement(B*) { cout << "use object raw ptr type version" << endl; return B(); } int implement(int) { cout << "use raw type version." << endl; return 0; } int implement(int*) { cout << "use raw ptr version." << endl; return 0; } int* implement(const int*) { cout << "use const raw ptr version." << endl; return 0; } /*统一调用接口*/ template <class T> inline RType interface(T param) { const type_info& Rtid = typeid(RType); const type_info& Tid = typeid(T); const char* Rname = Rtid.name(); const char* Tname = Tid.name(); bool bRet = compare_type(param, RType()); return implement(param);//static dispatch here. 编译期静态分发 } int main() { B b; A a; int value = 1; int *p = &value; const int* cp = p; A v1 = interface(a); B v2 = interface(&b); int v3 = interface(p); int* v4 = interface(cp); char ch = getchar(); return 0; }

通过一些模板技巧,使得模块内部可以根据用户输入数据类型,返回不同的数据,实现接口的统一,并在接口内实现静态分发。

另一种基于模板的静态分发,可以采用CRTP,以下是基于CRTP技术实现编译期多态的例子,仅供参考:

template<class T> class BaseObj { public: inline void Interface() { return static_cast<T*>(this)->Implement(); } inline void Implement() { } ~BaseObj() { static_cast<T*>(this)->Destory(); } inline void Destory() { } protected: // T m_subObj;// error. 基类中不能用子类来创建成员变量,这也是c++基本要求 }; class Drive :public BaseObj<Drive> { public: Drive() { m_handle = new int[4]; } //void Implement()//解开注释,观察效果, //{ // printf("Drive Implement.\r\n"); //} ~Drive() { printf("Drive Deconstructed.\r\n"); //Don't do any clear operation, put these into Destory call } void Destory() { printf("Drive Destoryed.\r\n"); delete[] m_handle; m_handle = nullptr;//important 防止Destory被重复调用导致重复释放 } private: int* m_handle; }; // 使用CRTP技术创建的不同子类对象,由于基类都是不一样的,因此不能统一放入容器中使用,可以用std::Any类型对它们进行一层包装,这样就可以放进容器了(参考:https://blog.csdn.net/yuanshenqiang/article/details/143984861)。 // c++ 模板类知识: // 可前置声明模板类,并给模板参数赋默认值,在使用的地方就可以不用给默认值: // template <class T, class TBase = CWindow, class TWinTraits = CControlWinTraits> class CWindowImpl; // template <class T, class TBase = CWindow, class TWinTraits = CControlWinTraits> class CWindowWithReflectorImpl; // template <class T, class TBase = CWindow> class CDialogImpl; // 这些模板类有多个模板参数,通过前置声明给一部分模板参数赋默认值,则在后续用的时候,可只给一个模板参数即可 int main() { Drive* d1 = new Drive; BaseObj<Drive>* dd1 = new Drive; dd1->Interface(); d1->Interface(); delete dd1; //d1->Destory();//手动调用Destory delete d1;//由基类的析构函数发起Destory调用 return 0; }

相比而言动态分发就是常规的虚函数——继承体系,基于该体系,可以实现各种设计模式。比如一个有趣的例子:c++的二次分发与访问者模式-CSDN博客

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询