函数模板&&类模板

函数模板:

     首先定义模板类型:

#include<iostream>
template<typename T>
T Sum(T a,T b)
{
	std::cout<< typeid(T).name()<<std::endl;
	return a + b;
}
int main()
{
	std::cout << Sum<int>(10,20)<< std::endl;
	std::cout<< Sum(20,30)<<std::endl;
	std::cout<< Sum(20.2,30.3)<<std::endl;
	std::cout<< Sum('a','b')<<std::endl;
	return 0;
}

   上面的代码是对两个数求和,其中<>是模板类型参数列表,其中在定义模板类型参数时  typename和class作用相同 

     那么在其编译阶段是怎么编译的?

         1.在定义点,只编译模板头部       2.在调用点,模板函数

 什么是模板函数函数?

        在调用点的时候,编译器先把函数模板转换为模板函数

#include<iostream>
/* 模板函数
int Sum(int a,int b)
{
	return a+b;
}
double Sum(double a,double b)
{
	return a+b;
}
char Sum(char a,char b)
{
	return a+b;
}
*/
template<typename T>
T Sum(T a,T b)
{
	std::cout<< typeid(T).name()<<std::endl;
	return a + b;
}
int main()
{
	std::cout << Sum<int>(10,20)<< std::endl;
	std::cout<< Sum(20,30)<<std::endl;
	std::cout<< Sum(20.2,30.3)<<std::endl;
	std::cout<< Sum('a','b')<<std::endl;
	return 0;
}

    4.模板的实参推演
        注意事项
            1.不能产生二义性
            2.有实参

#include<iostream>

template<typename T>
T Sum(T a,T b)
{
	std::cout<< typeid(T).name()<<std::endl;
	return a + b;
}
template<typename T>
T* Func()
{
	T* ptmp = new T();
	return ptmp;
}
int main()
{
	std::cout << Sum<int>(10,20)<< std::endl;//给出类型
	std::cout<< Sum(20,30)<<std::endl;//没有给定类型,但是给了实参,可以对实参进行推演
	Func<int>();//没有参数,但是给定了类型
	//Func();错误,没有给定类型,并且没有给实参,不能推理出类型
	return 0;
}

其错误是:

5.模板特例化:模板不能满足特殊类型的需要时,要是独立实现

           调用优先级:特例化的调用优先级 > 模板实例化版本(特例化应该符合模板的实例化逻辑

    例如:两个数比较,我们可以用 '>','<', '=='比较大小,但是当我们遇到字符串比较大小的时候,我们就不能这样比较了。于是我们可以把字符串比较大小独立写出来,使其特例化:  

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

template<class T>
bool compare( T v1, T v2)
{
	bool Result = false;
	if(v1>v2)
	{
		Result = true;
	}
	printf("普通类型比较\n");
	return false;
}
template <>
bool compare( char* v1, char* v2)
{
	bool Result = false;
	if( strcmp(v1,v2)==0)
	{
		Result = true;
	}
	printf("字符串比较\n");
	return Result;
}
int main()
{
	compare<int>(20,30);
	 char *p1="hello";
	char *p2="world";
	compare<>(p1,p2);
}

运行结果为:

 

6.模板的非类型参数:

      非类型模板参数是有类型限制的。一般而言,它可以是常整数(包括enum枚举类型)或者指向外部链接对象的指针

      浮点数和类对象(class-type)不允许作为非类型模板参数:

template<double VAL>            // ERROR: 浮点数不可作为非类型模板参数
double process(double v)
{
    return v * VAL;
}

运行结果为:

     

但是,我们可以稍微修改一下,就可以使用了:

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

template<double* PVAL>
double process(const double& x)
{
    return x * (*PVAL);
}
double a = 1.0;
double b=2.0;
template<int T>
int add(int p)
{
	return T * p;
}
int main()
{
	cout<< add<10>(20)<<endl;
	cout<< process<&b>(a)<<endl;
}

运行结果为:

     

7,模板的重载:

       1、重载:函数名相同,但函数的定义不同。编译系统会根据实参的类型和个数选择匹配度最高的函数进行调用。

     重载的过程规律(执行顺序如下):

       (1)首先会查找普通函数,寻找和使用函数名和参数类型最匹配的函数,如果找到则调用;

       (2)若普通函数没有,则在函数模板中查找,将模板实例化,若和调用的函数匹配,则调用该函数模板;

       (3)若经过上述两步还是未能找到,则可以通过类型转换转换进行参数匹配的函数重载,如果转换后能匹配则调用。

    上述就是重载函数的过程,如果到最后一步还未能找到匹配的函数,则会产生调用错误;若有多个可以匹配则会产生二义性。

         2、函数模板重载的分类:

            (1)函数模板可以和函数模板进行重载;

            (2)函数模板可以和显示特化后的模板进行重载;

           (3)函数模板和普通函数的重载。


注意:在模板重载的时候,调运优先级为:

        普通函数版本 > 模板特例化版本 > 普通模板版本(精确匹配) 

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


template<class T>
void func(T t)//普通模板
{
	cout<< "In generic version template "<<t<<endl;
}
template<class T>
void func(T* t)//指针特例化
{
	 cout << "In pointer version template "<< *t << endl;
}
void func(string* s)//普通函数
{
	 cout << "In normal function " << *s << endl;
}
int main()
{
	int i=10;
	func(i);//调用普通模板函数,推演
	func<int>(i);//调用普通模板函数,
	func(&i);//调用指针特例化,推演
	func<int>(&i);//调用指针特例化
	string a ="a";
	func(&a);//调用普通函数
	func(a);//调用普通模板函数
	func<string>(&a);//规定是模板,所以调用指针特例化,没有调用普通函数
	return 0;
}

运行结果为:

  

类模板:

  C++中,类模板的写法如下:

template <类型参数表>
class 类模板名{
    成员函数和成员变量
};

类型参数表的写法如下:

class类塑参数1, class类型参数2, ...

类模板中的成员函数放到类模板定义外面写时的语法如下:

template <类型参数表>
返回值类型  类模板名<类型参数名列表>::成员函数名(参数表)
{
    ...
}

用类模板定义对象的写法如下:

类模板名<真实类型参数表> 对象名(构造函数实际参数表);

如果类模板有无参构造函数,那么也可以使用如下写法:

类模板名 <真实类型参数表> 对象名;

类模板看上去很像一个类。下面以 Pair 类模板为例来说明类模板的写法和用法。

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

template <class T1,class T2>
class Pair{
public:
	T1 key;
	T2 value;
	Pair(T1 k,T2 v):key(k),value(v){};
	bool operator<(const Pair<T1,T2>&rhs);
};
template<class T1,class T2>
bool Pair<T1,T2>::operator<(const Pair<T1,T2>&rhs)
{
	return value < rhs.value ;
}
int main()
{
	Pair<string,int>student("Tom",20);
	Pair<string,int>student1("Jarry",30);
	if(student < student1)
	{
		cout<<"hello"<<endl;
	}
	else
	{
		cout<<"world"<<endl;
	}
	cout<<student.key<<" "<<student.value<<endl;
	return 0;
}

 运行结果为:

   

 

  在类模板中,调运的优先级为:普通方法 > 特例化方法 > 模板版本  

    类模板
       1.构造 析构函数不建议加模板类型参数
       2.其他建议加上模板类型

    1.类模板   选择性实例化  
         一定要在使用时指明实例化的类型
    typename 
    1.定义模板类型参数
    2.声明类型 

    1.拷贝构造函数的模板  ==》 构造函数 

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

template<typename T>
class CLink
{
public:
	CLink()
	{
		std::cout << "template<typename T> class CLink" << std::endl;
		phead = new Node();
	}
	CLink(const CLink<T>& rhs)
	{
		std::cout << "CLink(const CLink<T>& rhs)" << std::endl;
		phead = new Node();
		Node* ptail = phead;
		Node* pCur = rhs.phead->pnext;
		while (pCur != NULL)
		{
			Node* pnewnode = new Node(pCur->mdata);
			ptail->pnext = pnewnode;
			pCur = pCur->pnext;
			ptail = ptail->pnext;
		}
	}
	template<typename E>
	CLink(const CLink<E>& rhs)// 退化成构造函数
	{
		std::cout << "template<typename E> CLink(const CLink<E>& rhs)" << std::endl;
		phead = new Node();
		Node* ptail = phead;
		CLink<E>::Node* pCur = rhs.phead->pnext;
		while (pCur != NULL)
		{
			Node* pnewnode = new Node(pCur->mdata);
			ptail->pnext = pnewnode;
			pCur = pCur->pnext;
			ptail = ptail->pnext;
		}	
	}
	~CLink()
	{
		Node* pCur = phead;
		Node* pNext = pCur;
		while (pCur != NULL)
		{
			pNext = pCur->pnext;
			delete pCur;
			pCur = pNext;
		}
		phead = NULL;
	}
	bool InsertTail(T val)
	{
		Node* pnewnode = new Node(val);
		Node* ptail = phead;
		while (ptail->pnext != NULL)
		{
			ptail = ptail->pnext;
		}

		ptail->pnext = pnewnode;
		return true;
	}
	void Show()
	{
		Node* pCur = phead->pnext;
		while (pCur != NULL)
		{
			std::cout << pCur->mdata << " ";
			pCur = pCur->pnext;
		}
		std::cout << std::endl;
	}
	class Node;
	Node* Find(T val)//普通方法
	{
		std::cout << "Node* CLink<T>::Find(T)" << std::endl;
		Node* pCur = phead->pnext;
		Node* prt = NULL;
		while (pCur != NULL)
		{
			if (pCur->mdata == val)
			{
				prt = pCur;
				break;
			}
			pCur = pCur->pnext;
		}
		return prt;
	}
	template<typename E>
	Node* Find(E val)  //模板版本
	{
		std::cout << "template<typename E> Node* CLink<T>::Find(E)" << std::endl;
		Node* pCur = phead->pnext;
		Node* prt = NULL;
		while (pCur != NULL)
		{
			if (pCur->mdata == val)
			{
				prt = pCur;
				break;
			}
			pCur = pCur->pnext;
		}
		return prt;
	}
	template<>
	Node* Find(char* val) //特例化的版本
	{
		std::cout << "template<> Node* CLink<T>::Find(char*)" << std::endl;
		Node* pCur = phead->pnext;
		Node* prt = NULL;
		while (pCur != NULL)
		{
			if (strcmp(pCur->mdata,val) == 0)
			{
				prt = pCur;
				break;
			}
			pCur = pCur->pnext;
		}
		return prt;
	}
private:
	class Node
	{
	public:
		Node(T val = T()) :mdata(val), pnext(NULL){}
	public:
		T mdata;
		Node* pnext;
	};
	template<typename T>
	friend class CLink;
	Node* phead;
};
int main()
{
	CLink<int> ilink;//无参构造,我们调运函数的无参构造
	CLink<char> dlink(ilink);//拷贝构造函数,函数的拷贝构造只能拷贝构造相同数据类型的,不匹配,所以调用模板的拷贝构造
	CLink<int> ilink1(ilink);//拷贝构造,因为类型都是int类型,所以调用函数的拷贝构造
	for(int i=0;i<5;i++)
	{
		ilink.InsertTail(i+1);
	}
	ilink.Show();
	ilink.Find(5);//调运Find函数的普通函数
	ilink.Find<int>(5);//参数不符合特例化版本,所以调用模板;
	return 0;
}

运行结果为:

  

对整个类的特例化:

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

template<typename T1,
		 typename T2>
class Test
{
public:
	Test(T1 a, T2 b) :ma(a), mb(b)
	{
		std::cout << "template<typename T1,typename T2> class Test" << std::endl;
	}
private:
	T1 ma;
	T2 mb;
};

template<typename T1>
class Test<T1, int>
{
public:
	Test(T1 a, int b) :ma(a), mb(b)
	{
		std::cout << "template<typename T1> class Test<T1,int>" << std::endl;
	}
private:
	T1 ma;
	int mb;
};
int main()
{
	Test<int, double> test1(10, 20.1);//调运普通模板
	Test<double, int> test2(10.1, 20);//调用特例化模板
	Test<int, int> test3(10, 20);//调运特例化模板
	return 0;
}

 运行结果为:

  

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值