Skip to content

模板

在开始学习 模板(Template)之前有几句话需要明确:

  • 所谓泛型编程是独立于任何特定类型的方式编写代码。使用泛型编程时,我们需要提供具体程序实例所操作的类或者值;
  • 。我们给这些蓝图或者公式提供足够的信息,让这些蓝图或者公式真正的转变具体的类或者函数,这种转变发生在编译时;
  • 。也就是说,C++模板允许在定义类、函数时将类型作为参数。

模板概论

C++提供两种模板机制:(function template)和(class template)。

所谓函数模板,凡是函数体相同的函数都可以用这个模板代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现不同函数的功能。

C++实现泛型编程就是通过模板技术,其特点就是参数模板化template <typename T>告诉编译器后面紧跟着的函数或者类中出现T,不要报错,T是一个通用的数据类型。

总结:

  • 模板把函数或类要处理的数据类型参数化,表现为参数的多态性,称为类属。类属(类型参数化),又称参数模板
  • 模板用于表达逻辑结构相同,但具体数据元素类型不同的数据对象的通用行为

函数模板示例

定义函数模板,可以使用关键字template,后面跟一个或多个类型参数,用尖括号括起来。其中类型参数可以使用 typename 或 class 关键字来定义,推荐使用 typename 关键字,可以让代码更易读。

cpp
// 定义一个函数模板,用于比较两个数的大小
template <typename T>
bool compare(T a, T b) {
    std::cout << "calling compare(T a, T b)\n";
    return a > b;
}

模板定义以后在使用的时间有两种方式进行使用:

  • 自动类型推导(不指定传入参数的类型),必须要推导出一致的T才可以使用;
  • 显式指定类型
cpp
// 指定类型调用函数模板
compare<int>(1, 2);
// 不指定类型调用函数模板
// 编译器会自动推断模板参数类型 也叫做 模板实参推断
compare(1, 2);

// 指定类型调用函数模板
compare<double>(1.0, 2.0);

我们可以在函数模板中通过typeid来查看传入的类型,从而判断是否一致。

cpp
template <typename T>
bool compare(T a, T b) {
    std::cout << "calling compare(T a, T b)\n";
    std::cout << "a type: " << typeid(a).name() << std::endl;
    return a > b;
}

代码位置

模板的定义(声明及实现)应该放在.h文件中,因为模板的实例化是在编译时进行的,编译器需要知道模板的定义,才能进行实例化。

如果我们按照以往的分文件编写代码在头文件中声明在源文件中实现,那么在编译时就会出现链接错误,因为编译器不知道模板的定义。