C++中的模板类&模板函数
作者:TiRan_Yang
C++模板类&模板函数
模板类
模板类的定义使用 template<typename T>
或 template<class T>
,将具有相同功能的代码合并,增加代码的简洁性和易读性。
例如在计算凸包的例子中,传入点的类型可以是自定义的 Point
,也可以是 pcl::point
之类。
例如在头文件中的定义如下:
template<typename T> class POLYGON { public: POLYGON(); public: void convhull(std::vector<T> &input, std::vector<T> &result); };
模板函数
如模板类中的 convhull
函数就是模板函数,模板函数的输入为各种类型的点,将计算后的凸包存在 result
中。 convhull
的模板参数只有T,也可以为该函数增加其它的模板参数。
例如,增加参数 T1
:
template<typename T> class POLYGON { public: POLYGON(); template<typename T1> void test(T1 a); public: void convhull(std::vector<T> &input, std::vector<T> &result); };
以上为模板类和模板函数是如何定义的,接下来将介绍它们是如何初始化的。模板函数有隐式实例化和显示实例化,但模板类只有显式实例化。
1、隐式实例化
在模板函数的初始化在类的内部,即函数的实现在类的内部,例如实现 pointFromVeh2grd
,在调用隐式实例化的模板函数时,系统会自动适配模板参数T。
template<typename T> class POLYGON { public: POLYGON(); T pointFromVeh2grd(const T &ptVeh, const double &vehX, const double &vehY, const float &vehYaw){ return ptGrd; } template<typename T1> void test(T1 a); public: void convhull(std::vector<T> &input, std::vector<T> &result); };
2、显示初始化
模板函数的初始化在类的外部,模板类实例化 AXIS_CONVERT<int>
,这说明 AXIS_CONVERT
类只接受int类型的输入,如果输入类型,编译器会报错。
模板函数实例化 template void AXIS_CONVERT::test<double>(double);
同样 test
函数只接受 double
类型的输入。
//在源文件中进行显式初始化及实现 //显式初始化 template class AXIS_CONVERT<int>; template void AXIS_CONVERT::test<double>(double); //函数功能实现 template<typename T> template<typename T1> void AXIS_CONVERT<T>::test(T a) { std::cout<<a<<std::endl; }
C++函数模板特化,类模板特化
模版与特化的概念
1. 函数模版与类模版
C++中模板分为函数模板和类模板
- 函数模板:是一种抽象函数定义,它代表一类同构函数。
- 类模板:是一种更高层次的抽象的类定义。
2. 特化的概念
所谓特化,就是将泛型的东西搞得具体化一些,从字面上来解释,就是为已有的模板参数进行一些使其特殊化的指定,使得以前不受任何约束的模板参数,或受到特定的修饰(例如const或者摇身一变成为了指针之类的东东,甚至是经过别的模板类包装之后的模板类型)或完全被指定了下来。
模板特化的分类
针对特化的对象不同,分为两类:函数模板的特化和类模板的特化
1. 函数模板的特化
当函数模板需要对某些类型进行特化处理,称为函数模板的特化。
2. 类模板的特化
当类模板内需要对某些类型进行特别处理时,使用类模板的特化。
3. 特化整体上分为全特化和偏特化
(1)全特化
就是模板中模板参数全被指定为确定的类型。
全特化也就是定义了一个全新的类型,全特化的类中的函数可以与模板类不一样。
(2)偏特化
就是模板中的模板参数没有被全部确定,需要编译器在编译时进行确定。
全特化的标志就是产生出完全确定的东西,而不是还需要在编译期间去搜寻适合的特化实现,貌似在我的这种理解下,全特化的 东西不论是类还是函数都有这样的特点
(3)两者的差别
模板函数只能全特化,没有偏特化(以后可能有)。
模板类是可以全特化和偏特化的。
全特化的标志:template <>然后是完全和模板类型没有一点关系的类实现或者函数定义
偏特化的标志:template
函数模版特化:目前的标准中,模板函数只能全特化,没有偏特化
至于为什么函数不能偏特化,似乎不是因为语言实现不了,而是因为偏特化的功能可以通过函数的重载完成。
示例代码
1. 函数模板的特化
#include <iostream> #include <cstring> // 函数模板 template <class T> int compare(const T left, const T right) { std::cout <<"in template<class T>..." <<std::endl; return (left - right); } // 一个特化的函数模版 template < > int compare<const char*>(const char* left, const char* right) { std::cout <<"in special template< >..." <<std::endl; return strcmp(left, right); } // 这个其实本质是函数重载 int compare(char* left, char* right) { std::cout <<"in overload function..." <<std::endl; return strcmp(left, right); } int main( ) { compare(1, 4); const char *left = "abcdef"; const char *right = "wild_wolf"; compare(left, right); return 0; }
2. 类模板的特化
与函数模板类似,当类模板内需要对某些类型进行特别处理时,使用类模板的特化。
#include <iostream> #include <cstring> #include <cmath> #include"tt.h" // general version template<class T> class Compare { public: static bool IsEqual(const T& lh, const T& rh) { std::cout << "in the general class..." << std::endl; return lh == rh; } }; // specialize for float template<> class Compare<float> { public: static bool IsEqual(const float& lh, const float& rh) { std::cout << "in the float special class..." << std::endl; return std::abs(lh - rh) < 10e-3; } }; // specialize for double template<> class Compare<double> { public: static bool IsEqual(const double& lh, const double& rh) { std::cout << "in the double special class..." << std::endl; return std::abs(lh - rh) < 10e-6; } }; int main(void) { Compare<int> comp1; std::cout << comp1.IsEqual(3, 4) << std::endl; std::cout << comp1.IsEqual(3, 3) << std::endl; Compare<float> comp2; std::cout << comp2.IsEqual(3.14, 4.14) << std::endl; std::cout << comp2.IsEqual(3, 3) << std::endl; Compare<double> comp3; std::cout << comp3.IsEqual(3.14159, 4.14159) << std::endl; std::cout << comp3.IsEqual(3.14159, 3.14159) << std::endl; std::cout << hh<string>()("11") << std::endl; system("pause"); return 0; }
其中tt.h如下:
#include<string> using std::string; template<typename key> class hh { public: size_t operator()(const key& k) const { size_t hashVal = 0; key tmp = k; while (tmp > 0) { hashVal = 37 * hashVal + tmp % 10; tmp /= 10; } return hashVal; } }; template<> class hh<string> { public: size_t operator()(const string& key) { size_t hashVal = 0; std::cout << key << std::endl; for (char ch : key) { std::cout << "hasVal: " << hashVal << std::endl; hashVal = 37 * hashVal + ch; } return hashVal; } };
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。