|
|
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。出于同样的原因,第二个模板实参必须是常量表达式(不能传递变量)。函数 | 目录 | 名称可见性 |