👍作者主页:进击的1++
🤩 专栏链接:【1++的C++初阶】
文章目录
- 一,非类型模板参数
- 二,模板特化
- 三,模板分离编译
一,非类型模板参数
模板参数分为类类型模板参数与非类型模板参数。
类类型形参:出现在模板参数列表中,跟在class或typenam的后面的参数类型。
非类型形参:就是用一个常量作为模板的一个参数,在模板中可将该参数当成常量来使用。要注意的是:此常量必须为整型。
例:
template<class T,size_t N=100>
class Array
{
public:
void Print()
{
cout << "print" << endl;
}
private:
T arr[N];
};
二,模板特化
模板特化有函数模板特化和类模板特化。
函数模板特化:
我们先来看代码:
namespace hyp
{
template<class T1, class T2>
bool less(T1& a, T2& b)
{
return a < b;
}
class Date
{
public:
Date(int year, int month, int day)
:_year(year)
,_month(month)
,_day(day)
{}
bool operator<(const Date& d)const
{
if (_year < d._year)
{
return true;
}
else if (_year == d._year)
{
if (_month < d._month)
{
return true;
}
else if (_month == d._month)
{
if (_day < d._day)
{
return true;
}
else
return false;
}
else
return false;
}
else
return false;
}
void Print()
{
cout << "print" << endl;
}
private:
int _year;
int _month;
int _day;
};
}
int main()
{
hyp::Date a1(2023, 7, 25);
hyp::Date a2(2023, 7, 4);
hyp::Date a3(2023, 7, 16);
hyp::Date* p1 = &a1;
hyp::Date* p3 = &a3;
hyp::Date* p2 = &a2;
cout << hyp::less(a1, a2);
cout << hyp::less(p3, p2);
return 0;
}
当我们要进行某些特殊的比较时就会发生以上这种情况—>当我们想通过指向对象的指针比较日期大小时,结果就会有问题,为了解决这种问题,就有了模板特化。
解决上述问题,我们有如下代码:
template<class T>
bool less(T& a, T& b)
{
return a < b;
}
template<>
bool less<Date*>(Date*& a, Date*& b)
{
return *a < *b;
}
类模板特化:
类模板特化又有:全特化与偏特化。
全特化:
全特化即将模板参数列表中的所有参数都确定化。
我们直接来看代码:
template<class T1, class T2>
class Date
{
public:
void Print()
{
cout << "template<class T1,class T2>" << endl;
}
private:
T1 a;
T2 b;
};
template<>
class Date<int,char>
{
public:
void Print()
{
cout << "template<int,char>" << endl;
}
private:
int a;
char b;
};
}
int main()
{
hyp::Date<int, int> d1;
d1.Print();
hyp::Date<int, char> d2;
d2.Print();
hyp::Date<double, char> d3;
d3.Print();
return 0;
}
偏特化:
偏特化即对模板参数进一步进行条件限制的特化版本。
其有两种表现方式,先来看第一种:
template<class T1, class T2>
class Date
{
public:
void Print()
{
cout << "template<class T1,class T2>" << endl;
}
private:
T1 a;
T2 b;
};
template<class T1>
class Date<T1,char>
{
public:
void Print()
{
cout << "template<T1,char>" << endl;
}
private:
T1 a;
char b;
};
在上述代码中,我们将第二个参数特化为char。
这种表现方式,我们叫做部分特化。
接下来来看第二种:
template<class T1, class T2>
class Date
{
public:
void Print()
{
cout << "template<class T1,class T2>" << endl;
}
private:
T1 a;
T2 b;
};
template<class T1,class T2>
class Date<T1*,T2*>
{
public:
void Print()
{
cout << "template<T1*,T2*>" << endl;
}
private:
T1 a;
T2 b;
};
此种偏特化,对模板参数进行了更进一步的限制。
三,模板分离编译
我们假设有以下场景
当我们运行时,会发现链接错误。这是为什么呢?
在进行预处理时,我们的头文件会展开,在编译时,stu.c文件中的func先会去找有没有这个函数,在预处理阶段,头文件已经在我们的stu.c中展开,因此编译器就认为我们有这个函数,所以会根据某中规则形成符号记录在符号表中。而在func.c文件中编译器没有看到对模板函数的实例化,因此不会产生具体的func函数。所以在链接阶段时,我们在符号表中找不到对应的func函数,因此就会发生链接错误。
解决办法就是将函数的声明与定义放在一起,或者是模板定义的位置显式实例化,还可以使用函数的特化。
template<class T>
int func(T a)
{
return 0;
}
template<>
int func<int>(int a)
{
return 0;
}