c++学习笔记(六)—— 模板定义
模板定义
模板编译
编辑器遇到一个模板定于时,不会生成代码,而是在使用的时候生成代码。
所以在声明的时候,就需要知道定义。即函数模板和类模板的成员函数的定义通常放在头文件中。
类模板作用于声明类
在一个类模板的作用于内,我们可以直接使用模板名而不必指定模板实参。
模板类型的别名
template<typename T> using twin = pair<T, unsigned>;
twin<string> books; // books是pair<string, unsigned>
twin<int> booksNo; // booksNo是pair<int, unsigned>
显式实例化
目的是为了避免在多个文件中实例化相同模板,导致额外开销严重的问题
extern template declaration; //声明
template declaration; //定义
extern template class Blob<string>;
template int compare(const int& a, const int& b);
note:
1.当我们希望通知编辑器一个名字表示类型时,必须使用关键字typename,而不能使用class
2.成员模板不能是虚函数
模板类型转换
将实参传递给带模板类型的函数形参时,能够自动应用的类型转换只有const转换及数组或函数到指针的转换
template <typename T> T fobj(T, T);
template <typename T> T fref(const T&, const T&);
int a[10], b[42];
fobj(a, b); // fobj(int* ,int *)
fref(a, b); // 错误:数组类型不匹配
模板重载中,匹配的优先级
如果一个模板直接匹配,而另一个模板要类型转换才能匹配,则优先前者。
如果匹配的重载是提供同样好的匹配的话,按照以下规则判断
- 非模板函数和模板函数,优先前者
- 多个重载模板对一个调用提供同样好的匹配时,应选择最特例化的版本
- 如果都不满足,则此调用有歧义
规则2样例:
template <typename T> rep (const T &t);
template <typename T> rep (T *t);
string s("1");
const string* sp = &s;
rep(sp);
// 这里会调用第二个
// 【const T &t】本质上可以用于所有类型,【T *t】只能用于指针
// 所以第二个更特例化
扩展包写法理解
template <typename... Args> rep (const Args&... rest)
{
print(debug_rep(rest)...);
//如果调用 rep(1, 2, 3, 4);
//等价于 print(debug_rep(1), debug_rep(2), debug_rep(3), debug_rep(4))
print(debug_rep(rest...));
//如果调用 rep(1, 2, 3, 4);
//等价于 print(debug_rep(1, 2, 3, 4))
}