1. 非类型模板参数
模板参数分类型形参与非类型形参
类型形参: 出现在模板参数列表中,跟在class或者typename之类的参数类型名称。 ? 非类型形参: 就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用
```cpp
#define N 100
template<class T>
class array
{
private:
T _a[N];
};
int main()
{
array<int> a1;
array<double> a2;
return 0;
}
?
但如果我们想让a1是100,a2是1000该怎么做? 再添加一个非类型模板参数——常量
template<class T, size_t N>
class array
{
private:
T _a[N];
};
int main()
{
array<int,100> a1;
array<double,1000> a2;
return 0;
}
模板参数和函数参数十分类似,我们还可以给参数缺省值
template<class T, size_t N = 10>
class array
{
private:
T _a[N];
};
int main()
{
array<int> a0;
array<int,100> a1;
array<double,1000> a2;
return 0;
}
非类型模板参数限制:只能用于整型 int char long double
? ?
array
容器里也有一个array std::array 主要支持迭代器和[ ] 在C++11才增加的array
容器array与静态数组做对比 区别 :关于越界的检查 读检查不到,写才检查得到,但实写的检查也是有限的(抽查) 一个是函数调用 一个是原生指针
int main()
{
array<int, 10> a1;
int a2[10];
cout << sizeof(a1) << endl;
cout << sizeof(a2) << endl;
a1[15] = 0;
return 0;
}
? ?
2. 模板的特化
模板的特殊化处理 通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要特殊处理
实现场景: 不仅函数模板可以特化,类模板也可以特化
?
函数模板的特化
struct Date
{
Date(int year, int month, int day)
:_year(year)
, _month(month)
, _day(day)
{}
bool operator>(const Date& d) const
{
if ((_year > d._year)
|| (_year == d._year && _month > d._month)
|| (_year == d._year && _month == d._month && _day > d._day))
{
return true;
}
else
{
return false;
}
}
bool operator<(const Date& d) const
{
if ((_year < d._year)
|| (_year == d._year && _month < d._month)
|| (_year == d._year && _month == d._month && _day < d._day))
{
return true;
}
else
{
return false;
}
}
int _year;
int _month;
int _day;
};
template<class T>
bool Greater(T left, T right)
{
return left > right;
}
template<>
bool Greater<Date*>(Date* left, Date* right)
{
return *left > *right;
}
namespace haha
{
template<class T>
struct less
{
bool operator()(const T& x1, const T& x2) const
{
return x1 < x2;
}
};
template<>
struct less<Date*>
{
bool operator()(Date* x1, Date* x2) const
{
return *x1 < *x2;
}
};
}
int main()
{
cout << Greater(1, 2) << endl;
Date d1(2022, 7, 7);
Date d2(2022, 7, 8);
cout << Greater(d1, d2) << endl;
Date* p1 = &d1;
Date* p2 = &d2;
cout << Greater(p1, p2) << endl;
haha::less<Date> lessFunc1;
cout << lessFunc1(d1, d2) << endl;
haha::less<Date*> lessFunc2;
cout << lessFunc2(p1, p2) << endl;
std::priority_queue<Date, vector<Date>,haha::less<Date>> dq1;
std::priority_queue<Date*, vector<Date*>, haha::less<Date*>> dq2;
dq2.push(new Date(2022, 9, 27));
dq2.push(new Date(2022, 9, 25));
dq2.push(new Date(2022, 9, 28));
dq2.push(new Date(2022, 9, 29));
return 0;
}
不特化按指针比,特化了按指针指向的对象
?
类模板特化
全特化 偏特化 原则:有匹配就去走匹配的,没有的话将就一下也可以
template<class T1, class T2>
class Data
{
public:
Data() { cout << "Data<T1, T2>" << endl; }
private:
T1 _d1;
T2 _d2;
};
template<>
class Data<int, char>
{
public:
Data() { cout << "Data<int, char>" << endl; }
private:
};
template <class T1>
class Data<T1, int>
{
public:
Data() { cout << "Data<T1, int>" << endl; }
private:
};
template<class T1, class T2>
class Data<T1*,T2*>
{
public:
Data() { cout << "Data<T1*, T2*>" << endl; }
};
template<class T1, class T2>
class Data<T1&, T2&>
{
public:
Data() { cout << "Data<T1&, T2&>" << endl; }
};
template<class T1, class T2>
class Data<T1&, T2*>
{
public:
Data() { cout << "Data<T1&, T2*>" << endl; }
};
int main()
{
Data<int, int> d0;
Data<double, int> d1;
Data<int, char> d2;
Data<double, double> d3;
Data<double*, double*> d4;
Data<int*, char*> d5;
Data<int*, char> d6;
Data<int&, char&> d7;
Data<int&, double&> d8;
Data<int&, double*> d9;
return 0;
}
? ?
3.模板的分离编译
平时声明模板参数,可以用typename和class,没有区别 但是声明和变量分离时,用typename告诉编译器这是个类型,编译器分不清类型和变量
template<class T>
typename vector<T>::iterator vector<T>::insert(typename vector<T>::iterator pos, const T& x)
{
assert(pos >= _start);
assert(pos <= _finish);
if (_finish == _end_of_storage)
{
size_t len = pos - _start;
reserve(capacity() == 0 ? 4 : capacity() * 2);
pos = _start + len;
}
链接问题:有声明找不到定义 函数调用都会变成 call+一个地址 push_back();报错 原因:push_back没有被实例化
不用找 构造函数 size函数 operator[] 是不会去链接 因为它们在vector.h中是有定义的 vector实例化时,这些成员函数也实例化,直接就有定义了,那么编译阶段就可以确定地址了
找不到 push_back 、insert 这两个函数vector.h中只有声明没有定义,那么地址只能再链接阶段去确认。 报错证明链接阶段找不到。 T无法确定,所以没有实例化,那么push_back、insert就没有进符号表
·解决方案·:
- 模板的定义和声明不要分离到.h和.cpp (推荐
- 在.cpp里显示实例化 (麻烦,换个类型就要显示实例化一次
? ?
4. 模板总结
【优点 】
- 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
- 增强了代码的灵活性
【缺陷 】
- 模板会导致代码膨胀问题,也会导致编译时间变长
- 出现模板编译错误时,错误信息非常凌乱,不易定位错误
|