【C++】泛型编程 ③ ( 函数模板 与 普通函数 调用规则 | 类型匹配 | 显式指定函数模板泛型类型 )

2023-11-16 08:15:13 浏览数 (1)

一、普通函数 与 函数模板 的调用规则 - 类型匹配

1、类型匹配

上一篇博客 【C 】泛型编程 ② ( 函数模板与普通函数区别 ) 中 , 分析了 函数参数 类型匹配 下的 普通函数 与 函数模板 的调用规则 ;

为 函数模板 重载了 普通函数 , 普通函数有指定的类型 ;

代码语言:javascript复制
// 使用 template 关键字 声明函数模板 
// 告诉 C   编译器 开始使用 泛型编程 
// 定义的 T 是泛型类型 
// 声明了多个泛型, 可以只使用其中的部分类型
// 使用函数模板时 , 显式类型调用 必须 显式指定所有 泛型类型 的实际类型
template <typename T>
T add(T a, T b) {
	cout << "调用函数模板 T add(T a, T b)"<< endl;
	return a   b;
}

// 函数模板的 重载函数
// 重载是发生在 同一个作用域中
// 重写是发生在 父类 与 子类 之间
// C   编译器优先 调用 符合要求的 普通函数
// 如果普通函数不符合要求 , 则考虑调用 函数模板
int add(int a, int b) {
	cout << "调用普通函数 int add(int a, int b)" << endl;
	return a   b;
}

传入实参 , 调用 普通函数 还是 模板函数 , 是有一定的规则的 ;

普通函数 与 传入实参 类型匹配的 情况下 , 优先调用 普通函数 ,

如果 普通函数 无法匹配 则考虑调用 函数模板 ;

2、代码示例 - 类型匹配

代码示例 :

代码语言:javascript复制
#include "iostream"
using namespace std; 

// 使用 template 关键字 声明函数模板 
// 告诉 C   编译器 开始使用 泛型编程 
// 定义的 T 是泛型类型 
// 声明了多个泛型, 可以只使用其中的部分类型
// 使用函数模板时 , 显式类型调用 必须 显式指定所有 泛型类型 的实际类型
template <typename T>
T add(T a, T b) {
	cout << "调用函数模板 T add(T a, T b)"<< endl;
	return a   b;
}

// 函数模板的 重载函数
// 重载是发生在 同一个作用域中
// 重写是发生在 父类 与 子类 之间
// C   编译器优先 调用 符合要求的 普通函数
// 如果普通函数不符合要求 , 则考虑调用 函数模板
int add(int a, int b) {
	cout << "调用普通函数 int add(int a, int b)" << endl;
	return a   b;
}

// 普通函数 , 函数模板 调用 优先级
// 函数模板 会进行 严格类型匹配 , 不会进行 类型转换 ; 
// 
// 如果 符合 普通函数类型参数要求 , 优先调用普通函数 ; 
// 如果 没有 符合要求的 普通函数 , 则查看 模板函数 能否匹配 ; 
// 如果 模板函数 仍不能匹配 , 则查看 普通函数 类型转换能否匹配 ; 

int main() {

	int a = 10, b = 20;
	// 调用普通函数
	// 如果符合普通函数要求 优先调用普通函数
	int c = add(a, b);
	cout << "c = " << c << endl;

	double x = 50.0, y = 60.0;
	// 调用函数模板
	// 函数模板 自动类型推导
	double z = add(x, y);
	cout << "z = " << z << endl;
	
	// 控制台暂停 , 按任意键继续向后执行
	system("pause");

	return 0;
}

执行结果 :

调用普通函数 int add(int a, int b) c = 30 调用函数模板 T add(T a, T b) z = 110 Press any key to continue . . .

二、普通函数 与 函数模板 的调用规则 - 显式指定函数模板泛型类型

1、显式指定函数模板泛型类型

如果 函数调用时 , 显式指定函数模板类型 , 也就是在尖括号 <> 中指定了泛型类型 ,

此时 即使 参数类型 能 匹配 普通函数 ,

也要调用 函数模板 ;

在下面的代码示例中 , 传入的实参类型 都是 int 类型 , 完全符合 普通函数的 调用规则 ,

但是 使用 <int> 显示指定了 函数模板 的 泛型类型 ,

此时必须使用 函数模板 ;

代码语言:javascript复制
	int i = 30, j = 40;
	// 调用函数模板
	// 函数模板 显式类型调用
	int k = add<int>(i, j);
	cout << "k = " << k << endl;

2、代码示例 - 显式指定函数模板泛型类型

代码示例 :

代码语言:javascript复制
#include "iostream"
using namespace std; 

// 使用 template 关键字 声明函数模板 
// 告诉 C   编译器 开始使用 泛型编程 
// 定义的 T 是泛型类型 
// 声明了多个泛型, 可以只使用其中的部分类型
// 使用函数模板时 , 显式类型调用 必须 显式指定所有 泛型类型 的实际类型
template <typename T>
T add(T a, T b) {
	cout << "调用函数模板 T add(T a, T b)"<< endl;
	return a   b;
}

// 函数模板的 重载函数
// 重载是发生在 同一个作用域中
// 重写是发生在 父类 与 子类 之间
// C   编译器优先 调用 符合要求的 普通函数
// 如果普通函数不符合要求 , 则考虑调用 函数模板
int add(int a, int b) {
	cout << "调用普通函数 int add(int a, int b)" << endl;
	return a   b;
}

// 普通函数 , 函数模板 调用 优先级
// 函数模板 会进行 严格类型匹配 , 不会进行 类型转换 ; 
// 
// 如果 符合 普通函数类型参数要求 , 优先调用普通函数 ; 
// 如果 没有 符合要求的 普通函数 , 则查看 模板函数 能否匹配 ; 
// 如果 模板函数 仍不能匹配 , 则查看 普通函数 类型转换能否匹配 ; 

int main() {

	int a = 10, b = 20;
	// 调用普通函数
	// 如果符合普通函数要求 优先调用普通函数
	int c = add(a, b);
	cout << "c = " << c << endl;

	// 调用函数模板
	// 函数模板 显式类型调用
	int k = add<int>(a, b);
	cout << "k = " << k << endl;
	
	// 控制台暂停 , 按任意键继续向后执行
	system("pause");

	return 0;
}

执行结果 :

调用普通函数 int add(int a, int b) c = 30 调用函数模板 T add(T a, T b) k = 30 Press any key to continue . . .

0 人点赞