17.模板

yyyylllll / 2024-08-31 / 原文

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 模板与继承

普通类可以从类模板实例继承

模板可以从普通类继承

类模板可以继承类模板