什么是模板
与其他语言(如Java)中所提到的泛型相似,但C++中的templates(模板)要比其它语言中的泛型要更强大。模板有点像macro(宏),而泛型却非常受制于类型系统和其它因素。
模板允许定义一个根据你的用途进行编译的模板,你可以让编译器基于一套规则帮你写代码。
哪些情况需要用到模板
当一个函数需要传入的参数类型无法确定时,为了提高函数的复用率,可以定义一个模板。当程序中要调用这个函数时,可以根据传入的参数来由编译器生成实际的代码。
例如:
#include<iostream>
#include<string>
void print(int value)
{
std::cout<<value<<std::endl;
}
void print(std::string value)//函数重载
{
std::cout<<value<<std::endl;
}
int main()
{
print(5);
print("hello");
print(5.5f);//还需要写一次重载
std::cin.get();
}
如何只定义一次这个函数呢?
template<typename T>
void print(T value)
{
std::cout<<value<<std::endl;
}
template表明这里定义了一个模板,会在编译阶段被评估,所以这并不是一个真的函数,只有我们实际调用它的时候,这些函
数才被真正地创建。
typename T
是模板参数,这个例子中我们用选择typename作为模板参数的类型(也可以写作class),T作为名字,实际上是模板的参数名称,可以替换在例子中出现的类型。模板只有在它被调用时才会创建,否则它根本就不存在。
print<int>(5);//可以指定类型,这里得到的结果是:5
print<std::string>("hello");
template<typename T>
void print(T value)
{
std::cout<<value<<std::endl;
}
//等价于
void print(int value)
{
std::cout<<value<<std::endl;
}
进一步使用
模板绝不仅仅局限于类或者任何东西,也不会局限于函数,你可以基于模板创建一整个类。而且事实上,大量的C++标准模板库
同样完全使用了模板。例如:想在类中创建一个能够在定义的时候才给出大小的数组,从常识上来看是无法实现的,除非使用malloc函数或remalloc函数。
template<int N>
class Array
{
private int m_Array[N];
public int getSize() const
{
return this.N;
}
};
int main()
{
Array<5> array;
std::cout<<array.GetSize()<<std::endl;
std::cin.get();
}
可以看到,我们不是只能使用typename,我们可以使用整数或者其它的数据类型,来指定我们想要如何生成一个类和整个类。
让我们刚进一步,我想让数组的类型也是可变的,因此我希望能够在编译时指定这个数组实际包含的类型,我可以添加另一个模
板参数。
template<typename T,int N>
class Array
{
private T m_Array[N];
public T getSize() const
{
return this.N;
}
};
int main()
{
Array<int,5> array0;
Array<std::string,5> array1;
std::cout<<array.GetSize()<<std::endl;
std::cin.get();
}
这里我们创建的是一个可以自动创建的类,实际上这里与标准数组类在C++标准模板库中的工作方式非常相似(有2个模板参数,typename和size)。这有点像是C++的meta programming(元编程),相较于代码运行时的实际编程,我们像是在编译器在编译时进行编程。