模板
- 一、非类型模板参数
- 二、模板的特化
- 2.1 函数模板的特化
- 2.2 类模板的特化
- 2.2.1 全特化
- 2.2.2 偏特化
- 三、模板的分离编译
一、非类型模板参数
模板参数分为类型形参与非类型形参。
类型形参:出现在模板参数列表中,跟在class或者typename之类的参数类型名称。
非类型形参:就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。
就比如说我们需要一个动态数组的时候:
template <class T, size_t N = 10>
class Arr
{
private:
T a[N];
};
注意:
1️⃣ 浮点数、类对象以及字符串是不允许作为非类型模板参数的。
2️⃣ 非类型的模板参数必须在编译期就能确认结果。
二、模板的特化
2.1 函数模板的特化
class Stu
{
public:
Stu(const char* name, int age)
: _age(age)
{
strcpy(_name, name);
}
bool operator<(Stu& s)
{
return _age < s._age;
}
private:
char _name[5];
int _age;
};
template <class T>
bool Less(T a, T b)
{
return a < b;
}
int main()
{
Stu s1("a", 10), s2("b", 20);
cout << Less(s1, s2) << endl;
return 0;
}
但是如果要这么比较:
cout << Less(&s1, &s2) << endl;
这里就需要模板的特化
template <class T>
bool Less(T a, T b)
{
return a < b;
}
// Less 的特化
template <>
bool Less<Stu*>(Stu* a, Stu* b)
{
return *a < *b;
}
要注意这个是上面模板函数的特化,不能单独写。
2.2 类模板的特化
2.2.1 全特化
全特化即是将模板参数列表中所有的参数都确定化。
template <class T1, class T2>
class A
{
public:
A()
{
cout << "<T1 T2>" << endl;
}
private:
T1 a;
T2 b;
};
template<>
class A<double, double>
{
public:
A()
{
cout << "<double, double>" << endl;
}
};
int main()
{
A<int, int> a;
A<double, double> b;
return 0;
}
2.2.2 偏特化
template <class T1, class T2>
class A
{
public:
A()
{
cout << "<T1 T2>" << endl;
}
private:
T1 a;
T2 b;
};
// 偏特化
template<class T>
class A<T, char>
{
public:
A()
{
cout << "<T, double>" << endl;
}
};
三、模板的分离编译
当我们在头文件声明模板函数,而在源文件定义模板函数
// a.h
template<class T>
T Add(const T& left, const T& right);
// a.cpp
template<class T>
T Add(const T& left, const T& right)
{
return left + right;
}
这样运行起来会出现链接错误:
在源文件编译的时候,Add函数没有实例化,因此没有生成函数。但是编译器链接的时候会去找函数的地址,但是函数没有实例化没有地址,所以会出现链接错误。
解决办法:
1️⃣ 将声明和定义放到一个文件 “xxx.hpp” 里面或者xxx.h其实也是可以的。推荐使用这种。
2️⃣ 模板定义的位置显式实例化。这种方法不实用,不推荐使用