【C++】模板

零、前言:

看《STL源码剖析》这本书,发现到处是模板的影子。之前一直没怎么看模板,对它恨不熟悉,这台影响看书进度了。

工欲善其事必先利其器!模板主要以下知识点:

/*
	模板
		1.函数模板
			1.函数模板
			2.模板实例化
			3.模板函数
			4.模板的实参推演
			5.模板的特例化
				特例化版本  >  模板版本 
			
		2.类模板
	函数模板  
	模板的编译时机
	1.定义点  模板的头部
	2.调用点  模板函数
*/
//模板的类型参数列表
/*
	1.类型参数   typename / class 
	2.非类型参数 
		1.浮点型  类类型	
		2.常量
	模板重载
		1.普通函数
		2.模板特例化
		3.模板版本

*/

一、typename的意义

以下 template 声明式中 , class 和 typename有何区别?
            template<class T> class Widget;  //使用 "class"
            template<typename T> class Widget;  //使用 "typename"

答案:没有不同。当我们声明template 类型参数. class 和 typename 的意义完全相同。某些程序员始终比较喜欢class. 因为可以少打几个字。其他人(包括我〉比较喜欢 typename. 因为它暗示参数并非一定得是个class 类型。少数开发人员在接受任何类型时使用 typename. 而在只接受用户自定义类型时保留旧式的class。然而从 C++ 的角度来看,声明template 参数时,不论使用关键字class 或typename. 意义完全相同。

(摘自《Effective C++》第7章 条款42)

 

typename的用法:两个
    1.定义模板类型参数:这个用法中, 同class的用法一样,上文也说明二者不差别
    2.声明一个类型:主要在类模板中要注意,在模板中编译时,由于类模板的编译顺序,编译器可能不知道一个xxx是类型还是变量,所以需要用到typename去声明。

二、函数模板

1.为什么要有函数模板:节省代码

如下程序,实现了函数的重载,再试代码量大

    bool Compare(int a, int b)
	{
		return a > b;
	}
	bool Compare(double a, double b)
	{
		return a > b;
	}

 写成模板如下:

template<typename T>
bool Compare(T a, T b)//const char* a  const char* b
{
	std::cout << "bool Compare(T,T)" << std::endl;
	return a > b;
}

template<>   //针对特殊情形,但一定要在通用版本存在时才能用
bool Compare(const char* a, const char* b)
{
	return strcmp(a, b) > 0 ? true : false;
}
int main()
{
	Compare<int>(10, 20);
	Compare(10.1, 20.1);//double  double 
	Compare("hello", "world");
	return 0;
}

 例子二:

template<typename T, int SIZE>
void Sort(T arr[])
{
	//SIZE = 5;
	T tmp = T();
	for (int i = 0; i < SIZE - 1; i++)
	{
		for (int j = 0; j < SIZE - i - 1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
template<typename T>
void Show(T arr[], int len)
{
	for (int i = 0; i < len; i++)
	{
		std::cout << arr[i] << " ";
	}
	std::cout << std::endl;
}
int main()
{
	//int arr[] = { 12, 332, 4556, 89, 872, 3 };
	//int len = sizeof(arr) / sizeof(arr[0]);
	//Sort<int, len>(arr);
	//Show<int>(arr, 6);

	int a = 10;
	const int b = 20;
	const int c = a;//常量退化成常变量    
	return 0;
}

2.实例化:

隐式实例化指的是:在使用模板之前,编译器不生成模板的声明和定义实例。只有当使用模板时,编译器才根据模板定义生成相应类型的实例。如:int i=0, j=1;swap(i, j);  //编译器根据参数i,j的类型隐式地生成swap<int>(int &a, int &b)的函数定义。Array<int> arVal;//编译器根据类型参数隐式地生成Array<int>类声明和类函数定义。

显式实例化:当显式实例化模板时,在使用模板之前,编译器根据显式实例化指定的类型生成模板实例。如前面显示实例化(explicit instantiation)模板函数和模板类。其格式为:template typename function<typename>(argulist);template class classname<typename>;显式实例化只需声明,不需要重新定义。编译器根据模板实现实例声明和实例定义。

显示具体化:对于某些特殊类型,可能不适合模板实现,需要重新定义实现,此时可以使用显示具体化(explicite specialization)。显示实例化需重新定义。格式为:template<> typename function<typename>(argu_list){...};template<> class classname<typename>{...};

3.编译顺序:

三、类模板

1.用例、写法:

template<typename T>
class CLink
{
public:
	CLink()
	{
		phead = new Node();
	}
	void insertHead(T val)
	{
		Node* pnewnode = new Node(val);
		pnewnode->pnext = phead->pnext;
		phead->pnext = pnewnode;
	}
	class Node;
	Node* find(T val);
	void Show()
	{
		Node* pCur = phead->pnext;
		while (pCur != NULL)
		{
			std::cout << pCur->mdata << " ";
			pCur = pCur->pnext;
		}
		std::cout << std::endl;
	}
private:
	class Node
	{
	public:
		Node(T val = T()) :mdata(val), pnext(NULL){}
	public:
		T mdata;
		Node* pnext;
	};
	Node* phead;
};
template<typename T>
typename CLink<T>::Node* CLink<T>::find(T val)//typename
{
	Node* pCur = phead->pnext;
	while (pCur != NULL)
	{
		if (pCur->mdata == val)
		{
			return pCur;
		}
		pCur = pCur->pnext;
	}
	return NULL;
}
int main()
{
	CLink<int> cl;
	for (int i = 0; i < 10; i++)
	{
		cl.insertHead(i + 1);
	}
	cl.Show();
	auto rt = cl.find(6);
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值