先回忆下之前学过的模板
Add为一个类型形参模板,图中不管是将a,b还是c,d传参到Add函数中使用都会自动识别出数据类型并进行处理。
接下来让我们看一下这串代码,并思考:我们知道在这个我们自己写的array类中,里面的成员变量使用了指针实现了动态数组,那我们如果需要的是静态数组呢,该如何修改代码?
部分朋友可能会想到使用宏定义 #define N 10 ,T* array–>T array[N] 并且按照应用需求时刻来修改N值来实现对array静态数组的实现
但是如果我们面对的是这样的情况:a1数组中需要存放100个int类型的数据,a2数组中需要存放1000个double类型的数据,a3数组中需要存放10000个float类型数据。 我们使用这个宏定义还能解决问题吗?
接下来介绍我们今天将要学习的内容:非类型模板参数
模板参数分类类型形参与非类型形参。
类型形参即:出现在模板参数列表中,跟在class或者typename之类的参数类型名称。
非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用
如此使用非类型模板参数,就很好解决了上述问题
注意:
1.浮点数、类对象以及字符串是不允许作为非类型模板参数的。
2.非类型的模板参数必须在编译期就能确认结果
通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要特殊处理。比如:实现了一个专门用来进行小于的函数
在这里,如果按照我们的预期,代码执行结果应为:0,0,0
0,0,1? 这里为什么会出现1。大家可以很明显的看到p1,p2分别为地址,并不能直接进行比较,那我们该如何解决该问题呢?
此时,就需要对模板进行特化。即:在原模版类的基础上,针对特殊类型所进行特殊化的实现方式。模板特化中分为函数模板特化与类模板特化。
函数模板的特化步骤:
1.必须要先有一个基础的函数模板
2.关键字template后面接一对空的尖括号<>
3.函数名后跟一对尖括号,尖括号中指定需要特化的类型
4.函数形参表:必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报错
接下来,我们就对Less函数模板进行特化,处理日期类对象地址不能进行正确比较的问题
cout <
注意:一般情况下如果函数模板遇到不能处理或者处理有误的类型,为了实现简单通常都将函数直接给出。
bool Less(Date* left,Date* right)
{
return *left>*right;
}
这种实现简单明了,代码的可读性高,容易书写,因为对于一些参数类型辅助的函数模板,特化时特别给出,因此函数模板不建议特化。
全特化是将模板参数列表中所有的参数都确定化
template<class T1, class T2>
class Date
{
public:
Date()
{
cout << "Date" << endl;
}
private:
T1 _t1;
T2 _t2;
};
// 全特化
template<>
class Date<int ,char>
{
Date()
{
cout << "Date" << endl;
}
private:
int _t1;
char _t2;
};
偏特化:任何针对模版参数进一步进行条件限制设计的特化版本
1.部分特化
template<class T1, class T2>
class Date
{
public:
Date()
{
cout << "Date" << endl;
}
private:
T1 _t1;
T2 _t2;
};
//偏特化
template<class T1>
class Date<T1,char>
{
Date()
{
cout << "Date" << endl;
}
private:
T1 _t1;
char _t2;
};
2.参数更进一步的限制
偏特化并不仅仅是指特化部分参数,而是针对模板参数更进一步的条件限制所设计出来的一个特化版本。
// 参数类型进一步限制
template<class T1, class T2>
class Date<T1*, T2*>
{
public:
Date()
{
cout << "Data" << endl;
}
};
template<class T1, class T2>
class Date<T1&, T2&>
{
public:
Date()
{
cout << "Data" << endl;
}
};
template<class T1, class T2>
class Date
{
public:
Date()
{
cout << "Date" << endl;
}
private:
T1 _t1;
T2 _t2;
};
// 全特化
template<>
class Date<int ,char>
{
public:
Date()
{
cout << "Date" << endl;
}
};
//偏特化
template<class T1>
class Date<T1,char>
{
public:
Date()
{
cout << "Date" << endl;
}
};
// 参数类型进一步限制
template<class T1, class T2>
class Date<T1*, T2*>
{
public:
Date()
{
cout << "Data" << endl;
}
};
template<class T1, class T2>
class Date<T1&, T2&>
{
public:
Date()
{
cout << "Data" << endl;
}
};
int main()
{
Date<int, int> d1;
Date<double, double> d2;
Date<double, char> d3;
Date<char, char> d4;
Date<char*, char*> d5;
Date<char, int*> d6;
Date<double*, int*> d7;
Date<double&, int&> d8;
return 0;
}
【优点】
1.模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
2.增强了代码的灵活性
【缺陷】
1.模板会导致代码膨胀问题,也会导致编译时间变长
2.出现模板编译错误时,错误信息非常凌乱,不易定位错误