C++中的模板

1.非类型模板

模板参数分类类型形参与非类型形参。

类型形参即:出现在模板参数列表中,跟在class或者typename之类的参数类型名称。

非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。

template<class T,int N>
class Array
{
public:
private:
	T _a[N];
};
void test1()
{
	Array<int, 100>a1;        //  根据非类型模板参数开辟相应空间大小的arr数组
	Array<int, 1000>a2;
}

注意:

 浮点数类对象以及字符串是不允许作为非类型模板参数的。

非类型的模板参数必须在编译期就能确认结果。

2. 模板的特化

 在原模板类的基础上,针对特殊类型所进行特殊化的实现方式                                                           模板特化中分为函数模板特化类模板特化

为什么要进行模板特化

template<class T>
bool fun(T p1, T p2)
{
	return p1 < p2;
}
void test12()
{
	int a = 2;
	int b = 3;
	int* p1 = &a;
	int* p2 = &b;
	if (fun(p1, p2))
	{
		cout << "p1<p2" << endl;
	}
	else
	{
		cout << "p1>=p2" << endl;
	}
}


结果:p1>=p2  
结果显然式错的,为什么,因为将p1和p1直接作为int类型比较,
而p1先开辟空间(内存是从高地址先开辟空间),p1自然大于p2

函数模板的特化步骤:

1. 必须要先有一个基础的函数模板

2. 关键字template后面接一对空的尖括号<>

3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型

4. 函数形参表: 必须要和模板函数的基础参数类型完全相同(可以大于一个,但要与形参类型的个数匹配)


template<class T>
bool fun(T p1, T p2)
{
	return p1 < p2;
}

template<>
bool fun<int*>(int* p1, int* p2)
{
	return *p1 < *p2;
}
void test12()
{
	int a = 2;
	int b = 3;
	int* p1 = &a;
	int* p2 = &b;
	if (fun(p1, p2))
	{
		cout << "p1<p2" << endl;
	}
	else
	{
		cout << "p1>=p2" << endl;
	}
}
template<class T,class S>
void  fun(T p1, S p2)
{
	cout << "void  fun(T p1, S p2)" << endl;
	return;
}
template<>
void  fun<int*,char*>(int* p1, char* p2)
{
	cout << "void  fun<int*,char*>(int* p1, char* p2)" << endl;
	return;
}
void test12()
{
	int a = 1;
	int* p = &a;
	char arr[] = "GuYu";
	fun(p, arr);
}

结果:void  fun<int*,char*>(int* p1, char* p2)

3.类模板特化

3.1 全特化和偏特化
全特化:即是将模板参数列表中所有的参数都确定化。
偏特化:任何针对模版参数进一步进行条件限制设计的特化版本。

template<class T1, class T2>
class Date
{
public:
	Date()
	{
		cout << "原模板:template<class T1, class T2>" << endl;
	}
};

template< class T2>
class Date<int,T2>
{
public:
	Date()
	{cout << "偏特化:Date<int,T2>" << endl;}
};

template<>
class Date< int, char >
{
public:
	Date()
	{cout << "全特化 Date< int, char >" << endl;}
};


template<class T1, class T2>
class Date<T1*,T2*>
{
public:
	Date()
	{cout << "偏特化: Date<T1*,T2*>" << endl;}
};



template<class T1, class T2>
class Date<T1&,T2&>
{
public:
	Date()
	{cout << "偏特化: Date<T1&,T2&>" << endl;}
};


void test2()
{
	// 优先匹配更精确的模板
	Date<char, char>d0;    //-->原模板:template<class T1, class T2>
	Date<int, int>d1;      //-->偏特化:Date<int,T2>
	Date<int, char>d2;     //-->全特化 Date< int, char >
	Date<int*, int*>d3;    //-->偏特化: Date<T1*,T2*>
	Date<int&, int&>d4;    //-->偏特化: Date<T1&,T2&>
	Date<int, double>d5;   //-->偏特化:Date<int,T2>
}

4.模板分离编译

模板是不能声明与定义分离,

模板的编译机制:二次编译(Two-Phase Lookup)
模板的编译分为两个阶段:
1. 模板定义阶段:编译器只检查模板语法的正确性),不会生成具体代码。
2. 模板实例化阶段:当代码中实际使用模板(如 std::vector<int>)时,编译器才会根据模板生成具体的类或函数代码(即实例化)。

如果将模板的声明和定义分离:
声明文件(.h):仅包含模板的声明,编译器在编译其他源文件(.cpp)时无法看到定义,导致实例化失败。
定义文件(.cpp):虽然定义了模板,但其他源文件无法访问它(除非显式实例化),导致链接错误。

解决: 将声明和定义放到一个文件里面(.cpp或.h)。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值