C++函数模板声明和实现
重载函数使编程变得方便,因为对于执行类似操作的一组函数,只要记住一个函数名称即可。但是,每个函数都必须单独编写。例如,来看以下重载的 square 求平方函数:
函数模板不是实际的函数,而是编译器用于生成一个或多个函数的 "模具"。在编写函数模板时,不必为形参、返回值或局部变量指定实际类型,而是使用类型形参来指定通用数据类型。当编译器遇到对函数的调用时,它将检查其实参的数据类型,并生成将与这些数据类型配合使用的函数代码。
以下是一个 square 函数的函数模板:
在上面的 square 函数模板示例中,只使用了一个名为 T 的形参(如果有更多的话,它们将用逗号分隔)。在此之后,除了使用类型形参代替实际的数据类型名称之外,其他的都可以像往常一样写入函数的定义。在本函数模板示例中,以下是其函数头:
如前所述,编译器会检查对 square 的每次调用,并以适当的数据类型填充 T,例如,以下调用将使用 int 参数:
图 1 通过函数模板生成的两个函数实例
由于编译器在上面的程序中遇到了对 square 函数的两次调用,并且每次都使用了不同的形参类型,所以它生成了两个函数实例的代码(如图 1 所示):
请注意,在上边的程序中,模板出现在所有对 square 函数的调用之前。与常规函数一样,当编译器遇到对模板函数的调用时,必须已经知道模板的内容。因此,模板应放在程序的顶部附近或头文件中。
注意,函数模板仅仅是函数的规范,本身并不会导致使用内存。当编译器遇到对模板函数的调用时,才会在内存中创建该函数的实际实例。
int square(int number) { return number * number; } double square(double number) { return number * number; }这两个函数之间的唯一区别是它们的返回值及其形参的数据类型。在这种情况下,编写函数模板比重载函数更方便。函数模板允许程序员编写一个单独的函数定义,以处理许多不同的数据类型,而不必为每个使用的数据类型编写单独的函数。
函数模板不是实际的函数,而是编译器用于生成一个或多个函数的 "模具"。在编写函数模板时,不必为形参、返回值或局部变量指定实际类型,而是使用类型形参来指定通用数据类型。当编译器遇到对函数的调用时,它将检查其实参的数据类型,并生成将与这些数据类型配合使用的函数代码。
以下是一个 square 函数的函数模板:
template<class T> T square(T number) { return number * number; }函数模板由一个模板前缀标记开始,该模板前缀以关键字 template 开始,接下来是一组尖括号,里面包含一个或多个在模板中使用的通用数据类型。通用数据类型以关键字 dass 开头,后面跟着代表数据类型的形参名称。
在上面的 square 函数模板示例中,只使用了一个名为 T 的形参(如果有更多的话,它们将用逗号分隔)。在此之后,除了使用类型形参代替实际的数据类型名称之外,其他的都可以像往常一样写入函数的定义。在本函数模板示例中,以下是其函数头:
T square(T number)
其中,T 是类型形参或通用数据类型。该函数头定义了一个 square 函数,它返回一个 T 类型的值,并使用了一个形参 number,这也是 T 类型的数字。如前所述,编译器会检查对 square 的每次调用,并以适当的数据类型填充 T,例如,以下调用将使用 int 参数:
int y, x = 4;
y = square(x);
int square(int number) { return number * number; }但是,如果使用以下语句调用 square 函数:
double y, d = 6.2;
y = square(d);
double square(double number) { return number * number; }下面的程序演示了该函数模式的用法:
// This program uses a function template. #include <iostream> #include <iomanip> using namespace std; // Template definition for square function template <class T> T square(T number) { return number * number; } int main() { cout << setprecision(5); //Get an integer and compute its square cout << "Enter an integer: "; int iValue; cin >> iValue; // The compiler creates int square(int) at the first occurrence of a call to square with an int argument cout << "The square is " << square(iValue); // Get a double and compute its square cout << "\nEnter a double: "; double dValue; cin >> dValue; // The compiler creates double square(double)at the first // occurrence of a call to square with a double argument cout << "The square is " << square (dValue) << endl; return 0; }程序输出结果:
Enter an integer: 3
The square is 9
Enter a double: 8.3
The square is 68.89
图 1 通过函数模板生成的两个函数实例
由于编译器在上面的程序中遇到了对 square 函数的两次调用,并且每次都使用了不同的形参类型,所以它生成了两个函数实例的代码(如图 1 所示):
- 一个带有 int 形参和 int 返回类型的函数实例;
- 一个带有 double 形参和 double 返回类型的函数实例;
请注意,在上边的程序中,模板出现在所有对 square 函数的调用之前。与常规函数一样,当编译器遇到对模板函数的调用时,必须已经知道模板的内容。因此,模板应放在程序的顶部附近或头文件中。
注意,函数模板仅仅是函数的规范,本身并不会导致使用内存。当编译器遇到对模板函数的调用时,才会在内存中创建该函数的实际实例。