【c++修行之路】模板

模板

一般我们在实现一个函数的时候,都会使用模板,因为如果将类型写死,下次再使用的时候就要新写一个函数,尽管重载可以让名字方便,但每重载都要自己去写一个函数,这样非常麻烦,所以模板就是让编译器自己去推导,来生成对应的函数,从而实现泛型编程。

重载的缺点:
1、代码复用率低,只要有新类型出现,就得重新写函数。
2、安全性问题,只要一个重载函数出现问题,所有的重载函数都出错。

泛型编程:编写与类型无关的通用代码,是代码复用的手段,模板是泛型编程的基础。

函数模板

格式

template<class T>
bool Compare(T& t1,T& t2)
{
    
    
	return t1 < t2;
}

实例化

隐式实例化:
由编译器自己推导的称为隐式实例化,上面函数如果传入 <int,double> 会在编译期间就报错,因为编译器无法确定T是int还是double,可以显示强转或显式实例化。

int a = 10;
double b = 20;

//编译失败
Compare(a,b);

显式实例化:
如果类型不匹配,编译器会自动对不匹配的类型进行隐式类型转换,如果不行就报错。

int a = 10;
double b = 20;

//显式实例化
Compare<int>(a,b);

类模板

格式

template<class T1, class T2, ..., class Tn>
class 类模板名
{
    
    
	// 类内成员定义
};

ps:类外定义的函数需要加上类模板参数列表:

template <class T>
Vector<T>::func()
{
    
    }

实例化

类模板实例化需要指定类型,比如

vector<int> v;

其中 vector 不是 类型, vector 才是类型。

仿函数

正如其名,仿函数就是用类来模仿一个函数,实例如下:

template<class T>
class Compare
{
    
    
public:
	bool operator() (const T& t1,const T& t2)  
	{
    
    
		return t1 < t2;
	}
};

非类型模板参数

类型形参:
跟在class/typename后面的参数,int、double

非类型形参:
可以是具体的一个变量,但是不能是浮点数、字符、字符串等…

实例:

template<class T, size_t N = 100>
class test
{
    
    
};

模板特化

函数模板特化

为什么需要模板特化:
上面的比较函数在基本类型的比较中是没有问题的,但如果我们比较两个指针的内容显然是不合适的,我们又想要能够比较两个指针的内容,我们就可以选择特化:
示例:

template<class T>
bool Compare(T t1, T t2)
{
    
    
	return t1 < t2;
}

template<>
bool Compare<int*>(int* t1, int* t2)
{
    
    
	return *t1 < *t2;
}

但是注意:必须要和模板函数的参数列表完全相同:

template<class T>
bool Compare(T& t1, T& t2)
{
    
    
	return t1 < t2;
}

template<>
bool Compare<int*&>(int*& t1, int*& t2)
{
    
    
	return *t1 < *t2;
}

类模板特化

全特化

template<class T1,class T2>
class Data
{
    
    

};

template<>
class Data<int, char>
{
    
    

};

偏特化

//偏特化
template<class T1>
class Data<T1, char>
{
    
    

};
//进一步限制
template<class T1>
class Data<T1*, char>
{
    
    

};

模板分离编译

模板分离编译为什么会有问题:

先来回顾一下程序编译的过程:

解释:编译阶段拿到函数声明,可以顺利通过编译,但无法通过链接,因为链接时找不到函数地址(函数没有实例化)。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_73209194/article/details/130466118