1、模板类首先用来减少代码的重复,处理相同数据(只不过类型说明不一样如int,float,double),或者处理类似结构的据。
2、可以定义诸如下面的模板函数,这里的T类型也为模板类,我这里认定T的类型为vector<int>,vector<float>等;
template<typename T,int m> bool sortKdData(const T &t1, const T &t2) { return t1[m] < t2[m]; }
上述函数模板中,m不是作为sortKdData的一个参数,编译出现无法推断类型,有三个参数并不是因为m的问题而是在使用时也需实例化;
3、在一个模板函数中使用另一个模板函数如
template<typename T,int dim> T findMidValue(std::vector<T>& data) { sort(data.begin(), data.end(),sortKdData<T,dim>); auto pos = data.size() / 2; return data[pos]; }
这里可以看到需显式实例化sortKdData<T,dim>
dim必须作为一个常量指明,在buildKdTree函数中妄图使用变量调用模板函数无法通过编译,这里使用了一个switch
void KdTree<T>::buildKdTree(KdTreeNode<T>* root, std::vector<T>& orignaldata) { if (orignaldata.size() == 0) { return; } if (orignaldata.size() == 1) { root->data = orignaldata[0]; return; } root->left = new KdTreeNode<T>; root->right = new KdTreeNode<T>; root->left->parent = root; root->right->parent = root; int dim = findMaxDim(orignaldata); root->split = dim; AXIS seq = static_cast<AXIS> (dim); switch (seq) { case AXIS::X: root->data = findMidValue<T,0>(orignaldata); break; case AXIS::Y: root->data = findMidValue<T, 1>(orignaldata); break; case AXIS::Z: root->data = findMidValue<T, 2>(orignaldata); break; } std::vector<T> leftdata(orignaldata.begin(), orignaldata.begin() + orignaldata.size() / 2); std::vector<T> rightdata(orignaldata.begin() + orignaldata.size() / 2 + 1, orignaldata.end()); buildKdTree(root->left, leftdata); buildKdTree(root->right, rightdata); }4、模板类中声明友元类(此友元类也为模板类)
友元类必须在需定义的模板类之前声明;
牢记友元的原则
即原则一:朋友的朋友不是自己的朋友。
原则二:你认为别人是你的朋友但别人不认为你是他的朋友
提示:友元函数是全局的,声明在类中但并不属于类所有,可以在类声明中定义
template<typename T> class KdTree;//先于KdTreeNode声明 template<typename T> class KdTreeNode { friend class KdTree<T>;//需要使用模板参数T声明友元KdTree friend void operator<<(std::ostream & s,const KdTreeNode & kdnode); } KdTree是KdTreeNode认定的朋友,可以访问其私有成员,但是KdTreeNode的其他朋友并不是KdTree的朋友,所以KdTree对象无法访问重载的operator<<函数 将KdTree与KdTreeNode两个类分别写在两个文件里,包含KdTreeNode头文件后就可以使用KdTreeNode的友元函数opeartor<< 编译报错Link2019是因为友元的友元不是友元,还一直以为是模板类声明友元类出了问题