当函数模板遇到普通函数

先看代码,分析调用情况:

 1 #include<iostream>
 2 
 3 using namespace std;
 4 
 5 template <typename T1,typename T2>
 6 void test_fuc(T1& t1, T2& t2)
 7 {
 8     cout << "template...
";
 9 }
10 
11 template <typename T>
12 void test_fuc(T& t1, T& t2)
13 {
14     cout << "template...
";
15 }
16 
17 void test_fuc(int a, char b)
18 {
19     cout << "ordinary fuction...
";
20 }
21 
22 int main()
23 {
24     int a = 1;
25     char b = 0;
26     test_fuc(a, b);
27     test_fuc(a, a);
28     test_fuc(b, a);
29     cout << "hello...
";
30     return 0;
31 }

函数模板,也可以重载。当函数模板和普通函数名一样时,调用规则是:

1.如果普通函数和函数模板都有完全匹配的参数,优先调用普通函数的,如上面26行代码。

2.函数模板的参数必须严格一致,不能发生隐式转换,但是普通函数可以有隐式类型转换。这个测试需要把上面第一个模板函数屏蔽,调用28行代码,将访问普通函数,因为模板函数不能有隐式转化,必须严格匹配,普通函数则不同。

3.如果函数模板可以产生一个更好的匹配,优先调用函数模板。具体来说,27行代码,通过隐式类型转化其实是可以调用普通函数的,但是因为有一个完全匹配的模板函数,所以此时优先调用模板函数。

4.可以通过模板实参列表的语法限定编译器只通过模板匹配。

举例说明第四点(这也是为什么不动手就学不好c/c++的原因,这个也是因为自己在测试时发现的):

 1 template <typename T>
 2 void test_fuc(T t1, T t2)
 3 {
 4     cout << "template...
";
 5 }
 6 
 7 void test_fuc(int a, int b)
 8 {
 9     cout << "ordinary fuction...
";
10 }
11 
12 int main()
13 {
14     int a = 1;
15     char b = 0;
16     test_fuc(a, a);
17     test_fuc<>(a, a);
18     //test_fuc<int>(a,a);
19     cout << "hello...
";
20     return 0;
21 }

通过前面的几点分析可以知道,16行的调用将优先匹配普通函数,但要是我们就想调用模板函数,可以像17行那样,加一个空的模板参数列表,让其调用模板函数,也可以显式参数类型,如18行那样都可以让其绕过普通函数而强制调用模板函数。

再测(注意参数类型我已经更改):

 1 template <typename T>
 2 void test_fuc(T t1, T t2)
 3 {
 4     cout << "template...
";
 5 }
 6 
 7 void test_fuc(int a, char b)
 8 {
 9     cout << "ordinary fuction...
";
10 }
11 
12 int main()
13 {
14     int a = 1;
15     char b = 0;
16     test_fuc(a, b);
17     test_fuc<int>(a, b);
18     //test_fuc<>(a, b);
19     cout << "hello...
";
20     return 0;
21 }

第16行调用普通函数无可非议,17行,通过模板参数列表强制让其调用int类型的参数,这样也可以调用隐式转化过的模板函数,上面说的模板函数不能隐式转化,必须完全匹配是建立在隐式调用模板函数的前提下,通过模板参数列表显式调用模板函数,还是可以达到隐式转换的效果。但此时不能用空的模板参数,例如18行那样的调用会报错,要隐式转换你也得提供一个转换类型啊。

再改:

1 template <typename T>
2 void test_fuc(T& t1, T& t2)
3 {
4     cout << "template...
";
5 }

将模板函数参数换成引用,此时上面的代码将报错,不能从char转换到int &,这说明,模板函数的隐式转化和普通函数一样,必须要是可以隐式的类型,我们本就不能把一个char类型的绑定给一个int类型的引用。

再把上述引用类型改成指针,调用

test_fuc<int>(&a, &b);

同样报错,不能从char*转化成int*;可见,隐式类型转化的原则模板函数和普通函数都是需要遵循的。我们可以int和char或者double这样的转换,但是不可以用c++语言不支持的隐式类型转化规则。

原文地址:https://www.cnblogs.com/yangguang-it/p/6572494.html