函数模板
在前面的学习中,我们已经掌握了 C++ 的基础语法、流程控制、函数、数组、指针和面向对象等等内容。这些知识让我们能够编写结构化的程序,解决各种实际问题。
但是你有没有遇到过这样的情况:
你需要写一个函数来交换两个整数的值,然后又需要写一个函数来交换两个浮点数的值,甚至还要写一个函数来交换两个字符串的值。
按照之前的方法,我们首先想到的应该是建立三个函数,分别处理这类情况:
void swap_int(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
void swap_float(float &a, float &b) {
float temp = a;
a = b;
b = temp;
}
void swap_string(std::string &a, std::string &b) {
std::string temp = a;
a = b;
b = temp;
}功能的确实现了,但是很显然,这非常的不雅观。每次我们需要处理不同类型的数据时,都要重新编写一遍类似甚至相同的代码,这不仅增加了代码量,还容易出错和难以维护。
C++ 提供了一种强大的机制,能够让我们编写通用的代码,一次编写,适用于多种类型,这就是模板编程(Template Programming)。
在了解模板之前,我们需要先了解一下什么是泛型。
什么是泛型?
在编程中,泛型(Generic Programming)是一种让代码能够适用于多种数据类型的思想。它的核心目标是:编写与类型无关的算法和数据结构,让你的代码更加通用、灵活和可复用。
你可以把泛型理解为“类型参数化”——就像数学公式里的变量一样,代码中的类型也可以用参数来表示,等到实际使用时再指定具体类型。
在现代编程语言中,泛型的使用非常普遍。而 C++ 通过模板机制实现了强大的泛型编程能力。
注意
C 语言中并不支持泛型编程。
什么是模板?
模板是 C++ 提供的一种泛型编程工具。它允许我们在编写代码时不指定具体的数据类型,而是在使用时再确定类型。这样,我们就可以用同一份代码处理不同类型的数据,提高代码的复用性和灵活性。
你可以把模板想象成“代码工厂”,它可以根据你给定的类型参数,自动生成对应类型的代码。
模板的最大优势就是泛型——让代码可以适用于多种类型,避免重复劳动。例如:
- 写一个通用的排序函数,可以排序整数、浮点数、字符串等各种类型的数组
- 写一个通用的容器类(如 vector、map),可以存储任意类型的数据
- 写一个通用的算法,可以处理不同类型的数据结构
模板是 C++ 标准库(STL)中很多强大功能的基础,比如 std::vector<T>、std::sort、std::pair<T1, T2> 等等。
模板编程的核心思想是类型参数化。你可以在定义函数、类、结构体等时,使用模板参数来代替具体的类型。编译器在编译时会根据你实际传入的类型,自动生成对应的代码。
在 C++ 中有很多种模板的类型,如函数模板、类模板、变量模板等等。本节将主要介绍函数模板的使用方法。
函数模板的语法
函数模板的基本语法如下:
template <typename T> // 也可以使用 template <class T> 来代替,两者效果一致
返回类型 函数名(参数列表) {
// 函数体,在函数体内(参数列表也行),可以使用 T 作为类型来使用
}其中,模板参数可以有多个,使用逗号分隔:
template <typename T1, typename T2>
// ......以上方的 swap 函数为例,我们可以使用模板来简化代码,实现一个通用的交换函数:
#include <iostream>
#include <string>
using namespace std;
template <typename T>
void swap(T &a, T &b) {
T temp = a;
a = b;
b = temp;
}
int main() {
int x = 1, y = 2;
swap(x, y);
cout << x << " " << y << endl; // 输出 2 1
double a = 3.14, b = 2.71;
swap(a, b);
cout << a << " " << b << endl; // 输出 2.71 3.14
string s1 = "hello", s2 = "world";
swap(s1, s2);
cout << s1 << " " << s2 << endl; // 输出 world hello
return 0;
}这样,无论是 int、double、string 还是你自定义的类型,都可以用同一个函数来交换。
当然,你也可以显式的制定类型参数:
template <typename T>
T max(T x, T y) {
// ...Some code
}
int main() {
max<int>(1, 2);
max<double>(1, 2);
return 0;
}