《C++ Templates》 技巧性基础知识

关键字typename的相关问题:

首先需要注意的是当T存在内部类型的问题;

例如书上给出的示例:

template <typename T> void printcoll(const T& coll) {
	typename T::const_iterator pos;
	typename T::const_iterator end(coll.end());

	for (pos = coll.begin(); pos != end; ++pos) {
		std::cout << *pos << ' ';
	}
	std::cout << std::endl;
}

如上所示,注意下typename T::XXX的写法,旨在使用T类型中的类型;

这里给出的比较典型的例子就是关于STL库中的问题,例如每一个类中都有一个迭代器类型进行声明,如果想调用类似模板类型T中的类型,必须要在前面加上typename;


关于详细的类内this以及.template构造详见第九章;


成员模板的相关问题:

该章节主要想C++ primer一样,以不同类型的赋值函数为例子,介绍了相关的典型的成员函数模板问题;

其中和C++ primer类似,也介绍了使用STL时自定义内部存储单元的问题,即之前提到的缺省模板形式:

template <typename T, typename CONT = std::vector<T>> class stack {
private:
    CONT elems;
};

但是这也存在一个问题,就是进行类新建的时候需要指定两个模板参数stack<int,std::vector>s,这明显是不符合STL一般化描述的,因此可以使用“模板的模板参数”来进行处理;

 

模板的模板参数:

C++templates在这里相当不说人话,其实总结下来就是模板套里面再套一个模板(但是注意,套得模板必须是类模板),并且套入得模板由其他第一层模板参数进行实例化;

所以受上述stack<int,std::vector>s得问题可以得到解决,如果可以通过int初始化std::vector类型,直接可以在使用时候指定一个参数就可以;

声明形式如下:

《C++ Templates》 技巧性基础知识

k可以看到,在模板参数列表声明处,第二个是一个新的模板,里面的模板参数由类结构体内通过T显示指出;

也就是ELEM直接就是T类型;

这里注意一点,书上提到,如果不指定缺省allocator为ELEM类型,会导致分配空间无法进行;

本质原因是标准库中std::deque模板中第二个参数是allocator,为缺省值,如果不进行指定的话会导致deque得allocator和CONT得类型无法匹配,所以需要显式指定;

所以书上也提到了至关重要的一点:一定要考虑模板实参得缺省模板参数匹配问题! 

而对于后续得使用途中,如果没有显式得使用到ELEM等参数,可以直接留空写typename即可;

代码如下所示:

template <typename T, template <typename ELEM, typename = std::allocator<ELEM> >class CONT = std::deque> class Stack {
private:
	CONT<T> elems;
public:
	void push(const T&);
	void pop();
	T top() const;
	bool empty() const {
		return elems.empty();
	}
	template <typename T2, template <typename ELEM2, typename = std::allocator<ELEM2> >class CONT2> Stack<T, CONT>& operator=(const Stack<T2, CONT2>&);
};

template <typename T, template <typename, typename> class CONT> void Stack<T, CONT>::push(const T& elem) {
	elems.push_back(elem);
}

template <typename T, template<typename, typename> class CONT> template <typename T2, template <typename, typename> class CONT2> 
  Stack<T, CONT>& Stack<T, CONT>::operator=(const Stack<T2, CONT2>& op2) { if ((void*)this == (void*)&op2) { return *this; } Stack<T2, CONT2> tmp(op2); elems.clear(); while (!tmp.empty()) { elems.push_front(tmp.top()); tmp.pop(); } return *this; }

其中可以注意一下相关的写法问题,即不显式使用的参数没有必要写; 

《C++ Templates》 技巧性基础知识

 

 

零初始化问题:

零初始化问题主要是针对于模板初始化的相关问题,避免模板初始化的不安全问题;

尤其针对于内建元素,例如T为int等问题;

template <typename T> class myclass {
private:
	T x;
public:
	myclass():x(){}
};

对于模板中的未知类型得元素初始化调用x(),可以直接安全初始化,内置元素直接初始化为0;

 

字符串问题:

这里举例了字符串对比问题,也就是引用和非引用模板传递实参问题;

#include<iostream>
#include<stdlib.h>
#include<string>
using namespace std;

template <typename T> inline const T& rmax(const T& a, const T& b) {
	return a < b ? b : a;
}

int main() {
	//string a = "1239";
	//string b = "456";
	cout << rmax("1239", "456") << endl;
	system("pause");
	return 0;
}

 《C++ Templates》 技巧性基础知识

 

 会出现上述信息,但是如果直接通过a,b字符串来调用,并不会出现问题;

本质原因:引用和非引用字符串得传递类型不同

对于const string& 传递的是char[n]数组而,所以当数组元素个数不一样时,就会出现T模板参数不匹配的问题;

对于string形参,传递的是const char*指针,所以可以类型匹配;

 

一般的情况是显式指定并且使用重载,但是还是建议使用std::string形式,因为有可能出现比较的是指针地址大小的情况;

 

上一篇:《C++ Templates》深入模板基础(一)——模板参数问题(重点待补全)


下一篇:Enum, Generic and Templates