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)。
3866

被折叠的 条评论
为什么被折叠?



