|
|
10 2.5 |
operate
的函数,但其中一个函数有两个 int
类型的参数,而另一个函数有两个 double
类型的参数。编译器通过检查函数调用时传递的实参类型,来确定在每种情况下应调用哪个函数。如果使用两个 int
实参调用,它会调用具有两个 int
形参的函数;如果使用两个 double
实参调用,它会调用具有两个 double
形参的函数。int
版本将其参数相乘,而 double
版本则将它们相除。通常不建议这样做。一般而言,同名函数应具有至少相似的行为,但此示例表明,它们完全有可能行为不同。两个重载函数(即两个同名函数)具有完全不同的定义;从任何角度来看,它们都是不同的函数,只是恰好同名而已。
|
|
30 2.5 |
sum
函数针对不同的参数类型进行了重载,但函数体完全相同。sum
函数可以为多种类型重载,并且它们都具有相同的函数体是有道理的。对于这类情况,C++ 提供了定义具有泛型类型的函数的能力,这被称为函数模板。定义函数模板的语法与常规函数相同,只是在前面加上 template
关键字和一系列用尖括号 <> 括起来的模板参数:template <模板参数> 函数声明
class
或 typename
关键字后跟一个标识符来成为泛型模板类型。然后,该标识符可以在函数声明中像常规类型一样使用。例如,一个泛型的 sum
函数可以定义为:
|
|
class
还是 typename
来指定泛型类型没有区别(它们在模板声明中是 100% 的同义词)。SomeType
(一个在尖括号内的模板参数中的泛型类型)后,SomeType
就可以在函数定义的任何地方使用,就像其他任何类型一样;它可以用作参数的类型、返回类型,或用来声明该类型的新变量。在所有情况下,它都代表一个泛型类型,该类型将在模板被实例化时确定。名称 <模板实参> (函数实参)
sum
函数模板可以这样调用:
|
|
sum<int>
只是函数模板 sum
可能的实例化之一。在这种情况下,通过在调用中使用 int
作为模板实参,编译器会自动实例化一个 sum
的版本,其中每次出现的 SomeType
都被替换为 int
,就好像它是这样定义的:
|
|
|
|
11 2.5 |
T
作为模板参数名,而不是 SomeType
。这没有区别,而且 T
实际上是泛型类型中一个非常常见的模板参数名。sum
。第一次使用 int
类型的实参,第二次使用 double
类型的实参。编译器每次都实例化并调用了相应版本的函数。T
在 sum
函数内部也被用来声明该(泛型)类型的局部变量:
|
|
result
将是一个与参数 a
和 b
以及函数返回类型相同的变量。T
被用作 sum
参数的特定情况下,编译器甚至能够自动推导出数据类型,而无需在尖括号内显式指定。因此,不必像下面这样显式指定模板实参:
|
|
|
|
sum
时使用了不同类型的实参,编译器可能无法自动推导出 T
的类型。
|
|
x and y are equal |
are_equal
时使用了自动模板参数推导:
|
|
|
|
int
类型的值,而浮点字面量总是产生 double
类型的值。因此,10
的类型总是 int
,而 10.0
的类型总是 double
。class
或 typename
引入的类型,还可以包含特定类型的表达式:
|
|
20 30 |
fixed_multiply
函数模板的第二个参数是 int
类型。它看起来就像一个常规的函数参数,并且实际上也可以像常规参数一样使用。fixed_multiply
函数的不同实例化版本,因此该参数的值在运行时永远不会被传递:在 main
函数中对 fixed_multiply
的两次调用,实际上调用了函数的两个不同版本:一个总是乘以 2,另一个总是乘以 3。出于同样的原因,第二个模板实参必须是常量表达式(不能传递变量)。![]() 函数 | ![]() 目录 | ![]() 名称可见性 |