17.模板
17. 模板
17.1 函数模板(Function Template )
1.Function template (函数模板)
C++引入了带有泛型的函数模板
1.1. How to specify a type parameter? (如何声明类型参数)?
<typename T> : 描述性强,较好
<class T> : 易与类声明混淆,不推荐
2.Multiple type parameters (多个类型参数)
若函数模板有多于一个类型参数该怎么处理?
应该类型参数间用逗号分隔
template < typename T, typename S >
auto add (T x1, S x2) { //C++14
return (x1 + x2);
}
2.2. 编码规范
Names representing template types should be a single uppercase letter.
用于表示模板类型的名字应该使用一个大写字母
例如:
template<class T> ...
template<class C, class D> ...
3.Using Function Template (使用函数模板)
template <typename T, typename S>
auto add (T x1, S x2) { //C++14
return (x1 + x2);
}
int main () {
auto y = add ( 1, 2.0 );
return 0;
}
编译器根据函数调用的实参,生成函数模板的实例:
17.2 函数模版实例化
1.什么是函数模板实例化
1.1. 实例化:
函数模板只是蓝图,本身不是不是类型、函数。编译器扫描代码,遇到模版定义时,并不立即产生代码。确定模板实参后,编译器生成实际函数代码
1.2. 两种实例化方法 (确定模板实参的方法)
Explicit instantiation (显式实例化)
Implicit instantiation (隐式实例化)
2.Explicit instantiation (显式实例化)
强制某些函数实例化,可出现于程序中模板定义后的任何位置。
template < typename T >
void f(T s){
std::cout << s << '\n';
}
template void f<double>(double); // 实例化,编译器生成代码
// void f(*double* s) { // *T*: *double*
// std::cout << s << '\n';
// }
template void f<>(char); // 实例化 f<char>(char) ,推导出模板实参
template void f(int); // 实例化 f<int>(int) ,推导出模板实参
3.Implicit instantiation (隐式实例化)
编译器查看函数调用,推断模版实参,实现隐式实例化。
#include <iostream>
template<typename T>
void f(T s) {
std::cout << s << '**\n**';
}
int main(){
f<double>(1); // 实例化并调用 f<double>(double)
f<>('a'); // 实例化并调用 f<char>(char)
f(7); // 实例化并调用 f<int>(int)
void (*ptr)(std::string) = f; // 实例化 f<string>(string)
}
4.Instantiated function/class (实例函数/实例类)
4.1. C++11 (Section:14.7)
A function instantiated from a function template is called an *instantiated function*. A class instantiated from a class template is called an *instantiated class*.(由函数模板实例化得到的函数叫做“实例函数”,由类模板实例化得到的类叫做“实例类”)
非正规称呼:template function / template class
17.3 类模板
1.Class Template (类模板)
1.1类模板是将类中某些类型变为泛型,从而定义一个模板
1.2. Generic types of class members (类成员的泛型)
Data field member(数据域成员) : can be of a generic data *type* (可以成为泛型数据)
Function member(函数成员): return *type*, parameter *type*, local var *type* (返回值类型、参数类型、局部变量都可以成为泛型)
2.Class Templates
3.Syntax for class template (类模板的语法)
template<typename T>
class Stack{
public:
Stack();
bool empty();
T peek();
T push(T value);
T pop();
int getSize();
private:
T elements[100];
int size;
};
//模板前面放
//类型名后跟
template<typename T>
bool Stack<T>::empty()
{
return (size ==0);
}
//对比non-template class
// int Stack::peek()
template<typename T>
T Stack<T>::peek()
{
return elements[size - 1];
}
创建使用类模板时,类的声明和实现要放在同一个文件中,不能分离。
17.4 类模板实例化
1.显式实例化
template class Stack<int>; // 将类模板实例化为一个处理int类型的Stack类
2.隐式实例化
Stack<char> charStack; // 先实例化一个CharStack类(名字由编译器按规则生成)
// class CharStack { … char elements[100]; … };
// 然后用 CharStack charStack; 创建一个对象
Stack<int> intStack; // 实例化一个IntStack类
// class IntStack{ … int elements[100]; … };
// 然后用 IntStack intStack; 创建一个对象
vector intVector{1, 2, 3}; // C++17,模板类型参数根据初始化语句自动推导
// 实例化为 vector<int>
17.5 默认类型与非类型参数
1.Default type (默认类型)
1.1. Review: default parameter value (复习:参数的默认值)
int circle (int x, int y, int r=100);
1.2. Default type parameter (默认类型参数)
可以为类模板的类型参数指定一个默认类型
例如,指定泛型Stack的默认类型参数为 int
template<typename T = int>
class Stack{
...
};
1.3. 用默认类型定义一个对象
//a stack for int values
Stack<> stack;
函数模板不能使用默认类型参数。
2.Non-type Parameters (非类型参数)
在模板前缀中使用非类型参数,实例化模板时,非类型实参应该是对象
template<typename T, int capacity>
class Stack{
...
private:
T elements[capacity];
int size;
};
Stack<char, 100> charStack;
//对象作为非类型参数
template<typename T, Color c>
class Label{
……
};
Color color(0, 0, 255);
Label<char, color> label;
17.6 模板与继承
普通类可以从类模板实例继承
模板可以从普通类继承
类模板可以继承类模板