目录
1. 什么是函数模板?
2. 如何定义函数模板?
3. 如何使用函数模板?
4. 函数模板与函数重载的区别是什么?
5. 函数模板与类模板有何异同点?
1. 什么是函数模板?
- 函数模板是一种通用的函数描述,可以定义多个同名函数,以适应不同类型的参数。
2. 如何定义函数模板?
- 使用 template 关键字定义模板函数,语法为:```template <typename T>returnType functionName(T arg1, T arg2, ...){// function body}```
- typename 是一个关键字,表示类型参数。
- T 是函数的类型参数,可以是任何合法的 C++ 数据类型,包括内置类型和自定义类型。
3. 如何使用函数模板?
- 在调用函数时,编译器会根据实参类型确定调用哪个函数模板,语法如下:```functionName<type>(arg1, arg2, ...)```
- type 表示实参的数据类型,必须与函数模板中的类型参数 T 匹配。
以下时使用函数模板的示例:
-
定义一个函数模板
template <typename T> T maximum(T a, T b) {return a > b ? a : b; }
这个函数模板定义了一个名为
maximum
的函数,它有两个类型参数。它可以比较任意类型的值,并返回其中的最大值。 -
实例化函数模板
我们可以通过在函数名后面加上尖括号
<T>
来实例化函数模板,并指定类型参数 T 的具体类型。例如:int max_int = maximum<int>(3, 5); double max_double = maximum<double>(2.5, 1.8);
在第一行代码中,我们以
int
类型实例化了maximum
函数模板,并将其应用于整数值3
和5
。编译器会生成一个具体的函数实现,比较这两个整数值并返回其中的最大值。在第二行代码中,我们以
double
类型实例化了maximum
函数模板,并将其应用于浮点数值2.5
和1.8
。编译器同样会生成一个具体的函数实现,比较这两个浮点数值并返回其中的最大值。 -
自动推导类型 在C++函数模板实例化时,编译器会根据传入的实参类型来自动推导出模板形参的类型。 例如:
-
template<typename T> void print(T value) {std::cout << value << std::endl; }int main() {print(10); // 推导出T为intprint("hello"); // 推导出T为const char*return 0; }
在上述代码中,当我们调用
print(10)
和print("hello")
时,编译器会自动推导出T
分别为int
和const char*
。然后根据这个T
类型实例化出对应的函数模板。最终编译器将生成如下的代码:void print(int value) {std::cout << value << std::endl; }void print(const char* value) {std::cout << value << std::endl; }
4. 函数模板与函数重载的区别是什么?
- 函数重载是指在同一个作用域内定义多个同名函数,但它们的参数数量或类型不同。
- 函数模板是一种通用的函数描述,可以定义多个同名函数,以适应不同类型的参数。
通过函数模板生成的不同的函数之间是具有重载关系的。
具体来说,当我们使用函数模板时,编译器会根据实参的类型来确定最终调用的函数。如果有多个函数模板可以匹配实参类型,编译器会根据一定的匹配规则选择最合适的函数模板。如果最终的匹配结果对应的函数模板已经被实例化,那么就会调用相应的函数实现;否则,编译器会根据该类型参数的具体类型生成一个新的函数实现,并将其添加到重载候选函数集中。
因此,通过函数模板生成的不同函数之间是具有重载关系的,它们可以通过重载分辨符 operator()
来区分。例如,对于以下的函数模板:
template<typename T>
T add(T a, T b) {return a + b;
}
当我们分别调用 add(1, 2)
和 add(3.0f, 4.0f)
时,编译器会生成两个不同的函数实现:
int add(int a, int b) {return a + b;
}float add(float a, float b) {return a + b;
}
这两个函数之间就具有函数重载关系。
5. 函数模板与类模板有何异同点?
- 函数模板和类模板都是泛型编程的工具。
- 函数模板是用来生成函数的,类模板是用来生成类的。
- 函数模板中的类型参数可以应用于函数的参数、返回值和局部变量;类模板中的类型参数只能应用于类的成员变量和成员函数。
- 函数模板的一些常见使用场景:
- 容器类的泛型算法,如 STL 中的 sort()、find() 等。
- 数学库中的数值计算函数,如求平方根、幂函数等。
- 模板元编程,即使用模板来实现某些编译时的计算或操作。
-
类模板是一种通用的类描述,可以根据不同的类型参数生成多个具体的类实现。下面是类模板的一些常见使用场景:
1. 容器类的泛型实现:STL 中的 vector、list、map 等容器都是通过类模板实现的。这些容器类需要支持不同类型的元素,因此需要通过类型参数来实现泛型。
2. 模板化算法:与容器类相似,许多算法也需要支持不同类型的数据。例如,可以用类模板来实现排序、查找、匹配等算法。
3. 模板元编程:模板元编程是指利用 C++ 模板系统进行编译时计算的技术。可以通过类模板来实现许多元编程技巧,例如在编译期计算阶乘、斐波那契数列、类型列表等。
4. 设计模式:设计模式是一些经过验证的、可复用的解决方案,用于解决软件设计中的常见问题。类模板是实现许多设计模式的基础,如单例模式、策略模式、桥接模式、享元模式等。
5. 库的开发:C++ 库的开发通常需要使用到类模板。库的设计者需要考虑到用户可能会使用不同类型的数据,因此要使用类模板来实现泛型。