C++ 模板(进阶)

Posted L_add

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ 模板(进阶)相关的知识,希望对你有一定的参考价值。

非类型模板参数

模板参数分类分为类型形参与非类型形参
类型形参:出现在模板参数列表中,跟在class或typename之类的参数类型名称
非类型形参:就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可以将该参数当成常量来使用。

/模板参数
//类型模板参数
//非类型模板参数 --int常量
template<class T,size_t N>
class Array
{
public:
	void f()
	{
		N = 100;
	}
private:
	T _a[N];
};
int main()
{
	Array<int,100> aa1;//100
	Array<int,1000> aa2;//1000
	//aa1.f();//报错
	return 0;
}

注意:

  • 浮点数、类对象以及字符串是不允许作为非类型模板参数的
template <class T>
bool IsEqual(const T& left, const T& right)
{
	return left == right;
}
int main()
{
	cout << IsEqual(1, 2) << endl;
	cout << IsEqual(1.1, 2.2) << endl;
	char p1[] = "hello";
	char p2[] = "hello";
	cout << IsEqual(p1, p2) << endl;//不相等
	char* p3 = "hello";
	char* p4 = "hello";
	cout << IsEqual(p3, p4) << endl;//相等
}

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

模板的特化

概念

通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊的类型的可能会得到一些错误的结果。编译器默认函数模板或者类模板不能正确处理需要逻辑 ,需要进行特殊化处理。

//针对字符串类型要特殊化处理 -- 写一份特殊的函数模板出来
//函数模板的特化
//template <>
//bool IsEqual<const char*>(const char* const& left, const char* const& right)
bool IsEqual(const char* left,const char* right)
{
	return strcmp(left, right) == 0;
}
int main()
{
	cout << IsEqual(1, 2) << endl;
	cout << IsEqual(1.1, 2.2) << endl;
	char p1[] = "hello";
	char p2[] = "hello";
	cout << IsEqual(p1, p2) << endl;//1
	char* p3 = "hello";
	char* p4 = "hello";
	cout << IsEqual(p3, p4) << endl;//1
}

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

函数模板特化

函数模板特化的步骤:

  1. 必须要有一个基础的函数模板
  2. 关键字template<>
  3. 函数名后跟<>,<>内中指定需要特化的类型
  4. 函数形参表:必须要和模板函数的基础类型完全相同。
template <>
bool IsEqual<const char*>(const char* const& left, const char* const& right)

{
	return strcmp(left, right) == 0;
}

注意:一边情况下如果函数模板遇到不能处理或处理有误的类型,为了实现简单通常都是将该函数直接给出

bool IsEqual(const char* const& left,const char* const& right)
{
	return strcmp(left, right) == 0;
}

类模板特化

template <class T1,class T2>
class Date
{
public:
	Date()
	{
		cout << "Date <T1,T2>" << endl;
	}
private:
	T1 _d1;
	T2 _d2;
};
int main()
{
	Date<int, int> d1;
	Date<int, double> d2;
	return 0;
}

全特化

全特化是将模板参数列表中所有的参数都确定化

//假设针对T1 T2 是 int int 想做特殊化处理 -》类模板特化
template<>
class Date<int, int>
{
public:
	Date()
	{
		cout << "Date <int,int>" << endl;
	}

};
int main()
{
	Date<int, int> d1;
	Date<int, double> d2;
	return 0;
}


特化的本质:显示指定实例化的模板

偏特化

偏特化:任何针对模板参数进一步进行条件限制设计的特化版本。

/将第二个参数特化为int --- 偏特化
template<class T>
class Date<T,int>
{
public:
	Date()
	{
		cout << "Date <T,int>"<< endl;
	}

};
int main()
{
	Date<int, int> d1;
	Date<int, double> d2;
	Date <char, int> d3;
	return 0;
}

偏特化有两种形式:

  • 部分特化:将模板参数类表中的一部分参数特化
  • 将参数更进一步的限制:偏特化并不仅仅是指特化部分的参数,而是针对模板参数更进一步的条件限制所设计出来的一个特化版本
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;
	}

};
int main()
{
	Date<int, int> d1;
	Date<int, double> d2;
	Date <char, int> d3;
	Date<int*,char*> d4;
	Date<int&, double&> d5;
	return 0;
}

模板的分离编译

一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式

模板的分离编译

假设,模板的声明与定义分离开,在头文件中进行声明,源文件中完成定义

解决方法

  1. 将声明和定义放到一个文件 xxx.cpp里或xxx.h
  2. 模板定义的位置显式实例化

模板的总结

优点

  1. 模板复用代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此产生

  2. 增强代码的灵活性
    缺点:

  3. 模板会导致代码膨胀问题,也会导致编译时间变长

  4. 出现模板编译错误时,错误信息凌乱,不容易定位错误

以上是关于C++ 模板(进阶)的主要内容,如果未能解决你的问题,请参考以下文章

C++初阶第十三篇—模板进阶(非类型模板参数+模板特化+模板的分离编译)

C++之模板进阶

C++之模板进阶

C++——模板进阶

C++模板进阶

C++模板进阶