模板小结

114 阅读2分钟

模板是泛型编程基础,即编写类型无关的代码,可以减少重复代码的出现。

函数模板

函数重载是指一系列同名函数,它们的函数特征标不同。或参数类型不同,或参数个数不同,或这二者都不同。但如果是要实现功能类似的函数,只是具体类型不同,如:

int add(int, int);
float add(float, float);
double add(double, double);

则这三个函数的函数体几乎一模一样。此时,就可以定义一个通用的模板:

template<typename T,char op = '+'>
T Operator(T a,T b){
    if(op=='+')return a+b;
    else if(op=='-')return a-b;
    //...
}

//main()
std::cout<<Operator(2,3)<<std::endl;//5
std::cout<<Operator<int,'-'>(4,2)<<std::endl;//2

上述模板定义中,T是类型参数,可以表示任意类型;op是非类型参数,提供了默认值+,但非类型参数一般不能是浮点型或者类类型。在main()中,可以看到编译器能够根据实参推断模板参数,也可以显式指定。为了不出错,建议全部显式指定。

类模板

类是C++中的核心概念,也可以编写通用类模板。常用的vectorstack等都是基于模板实现的。

//.h
template<typename T>
class ownVector{
public:
    typedef T* iter;//or using iter = T*;
    
    ownVector()=default;
    ownVector&operator=(const ownVector&);
    
    template<typename T1>
    ownVector(T1 v);
    
    iter begin();
    //iter end();
};

template<typename T>
ownVector<T>&ownVector<T>::operator=(const ownVector<T>&){}

template<typename T>
template<typename T1>
ownVector<T>::ownVector(T1 v){}

template<typename T>
typename ownVector<T>::iter ownVector<T>::begin(){}

类外使用模板名时,需要标明模板参数。typename关键字既可以声明类型参数,也可以用来通知编译器某个名字代表的是类型:typename ownVector<T>::iter
类模板的成员函数也可以是函数模板。成员函数模板和类模板拥有各自独立的模板参数。如果在类外书写成员函数定义,则需要先写类模板的模板参数列表,再写成员函数模板的模板参数列表。

其它

模板在使用时才会实例化。模板定义并不会生成相关代码,只有在实例化时才生成特定版本的代码。由于实例化需要找到相关定义,因此,模板的编写一般都放在.h文件中。

由于每次调用都会生成实例化代码,如果多次使用就会生成多个相同模板实例,增加了很多编译时间。可以通过“显式实例化”来避免这种情况:template template-name<template-parameters>;,该语句表明编译器会实例化出一份代码供本文件使用。如果在其它文件中也想使用该定义,则可以进行“实例化声明”:extern template template-name<template-parameters>