模板参数分 类型形参 和 非类型形参
类型形参:出现模板参数列表中,跟在class或者typename之类的参数类型名称 非类型形参:用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当常量来使用
namespace A
{
template<class T,size_t N = 10>
class arr
{
public:
T& operator[](size_t n) { return _arr[n]; }
size_t size() const { return _size; }
bool empty() const { return 0 == _size; }
private:
T _arr[N];
size_t _size;
};
}
其中N就是非类型形参 浮点数,类对象,字符串不可以当非类型模板参数 非类型的模板参数必须在编译期就能确认结果
通常情况下,使用模板可以实现一些与类型无关的代码,但是对于特殊类型也需要特殊处理
class Num
{
public:
Num(int a):_a(a){}
bool operator<(Num& b) { return _a < b._a; }
private:
int _a;
};
template<class T>
bool Less(T left, T right)
{
return left < right;
}
int main()
{
cout << Less(1, 2) << endl;//正确
Num n1(1);
Num n2(2);
cout << Less(n2, n1) << endl;//正确
Num* p2 = &n1;
Num* p1 = &n2;
cout << Less(p2, p1) << endl;//这里比的是地址 不是我们要的
return 0;
}
为了在对比指针时,转换为我们想要的对比方式,就需要对模板进行特化,就是在原模版类的基础上,针对特殊类型模板进行特殊化的实现方式,模板特化分为函数模板特化与类模板特化
template<class T>
bool Less(T left, T right)
{
return left < right;
}
template<>
bool Less<Num*>(Num* left, Num* right)
{
return *left < *right;
}
全特化就是将模板参数列表中的所有参数都确定化
template<class T1,class T2>
class Num
{
public:
Num(T1 a1,T2 a2):_a1(a1),_a2(a2){}
private:
T1 _a1;
T2 _a2;
};
template<>
class Num<int,char>
{
public:
Num(int a1, char a2) :_a1(a1), _a2(a2) {}
private:
int _a1;
char _a2;
};
不完全的特化类型
template<class T1,class T2>
class Num
{
public:
Num(T1 a1,T2 a2):_a1(a1),_a2(a2){}
private:
T1 _a1;
T2 _a2;
};
template<class T1>
class Num<T1, int>
{
public:
Num(T1 a1, int a2) :_a1(a1), _a2(a2) {}
private:
T1 _a1;
int _a2;
};
特殊偏特化
template<class T1, class T2>
class Num<T1*,T2*>
{
public:
Num(T1* a1, T2* a2) :_a1(a1), _a2(a2) {}
private:
T1* _a1;
T2* _a2;
};
template<class T1, class T2>
class Num<T1&,T2&>
{
public:
Num(T1& a1, T2& a2) :_a1(a1), _a2(a2) {}
private:
T1& _a1;
T2& _a2;
};
把多个源文件实现,单独编译,然后链接成单一可执行文件的过程叫做分离编译模式
在C++中,模板是一种允许程序员编写通用代码的工具,可以适应不同的数据类型和场景。然而,模板本身并不生成代码,只有当模板被实例化时,编译器才会根据模板定义生成相应的代码。这意味着,模板的实例化是在编译时进行的,而不是在链接时。
模板定义不可见:当模板的声明与定义分离,并且定义在另一个文件中时,编译器在实例化模板时可能找不到对应的模板定义。由于模板的实例化是在编译时进行的,如果编译器在实例化模板时无法访问到模板的完整定义,那么它将无法生成正确的代码,从而导致编译或链接错误。 符号表问题:符号表记录了程序中所有符号(如函数名、变量名等)的信息。对于模板来说,如果模板在某个源文件中被实例化,那么实例化后的函数或对象将会出现在该源文件的符号表中。但是,如果模板的声明与定义分离,且定义在另一个文件中,而这个文件在链接前没有被正确编译或包含,那么实例化后的符号可能就不会出现在最终的符号表中,从而导致链接错误。
1.把声明和定义放到同一个文件里 2.模板定义的位置显式实例化
实例化:
// MyClass.cpp
#include "MyClass.h"
// 显式实例化 MyClass<int> 和 MyClass<double>
template class MyClass<int>;
template class MyClass<double>;
优点
缺点