我是靠谱客的博主 敏感啤酒,最近开发中收集的这篇文章主要介绍C++ 函数模板的重载与实参推断函数模板的重载函数模板的实参模板实参推断过程中的类型转换为函数模板显式地指明实参显式的指明实参时可以应用正常的类型转换,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

    结合网上的资料,对函数模板的重载与实参推断做一个总结。

函数模板的重载

  当需要对不同的类型使用同一种算法时,为了避免定义多个功能重复的函数,可以使用模板。然而,并非所有的类型都使用同一种算法,有些特定的类型需要单独处理,为了满足这种需求,C++允许对函数模板进行重载。

  例如,当交换基本类型和交换两个数组时,虽然功能都是交换,但是使用的方法却不相同,交换两个数组唯一的办法就是逐个交换所有的数组元素。

template<class T> void Swap(T &a, T &b){
    T temp = a;
    a = b;
    b = temp;
}
template<typename T> void Swap(T a[], T b[], int len){
    T temp;
    for(int i=0; i<len; i++){
        temp = a[i];
        a[i] = b[i];
        b[i] = temp;
    }
}

函数模板的实参

  在使用类模板创建对象时,需要显式的指明实参,例如:

template<typename T1, typename T2> class Point;
Point<int, int> p1(10, 20);  //在栈上创建对象
Point<char*, char*> *p = new Point<char*, char*>("东京180度", "北纬210度");  //在堆上创建对象

对于函数模板,调用函数时可以不显式的指明实参,编译器会自动推导出T的类型,例如:

//函数声明
template<typename T> void Swap(T &a, T &b);
//函数调用
int n1 = 100, n2 = 200;
Swap(n1, n2);
float f1 = 12.5, f2 = 56.93;
Swap(f1, f2);

模板实参推断过程中的类型转换

普通函数调用时的类型转换

  • 算数转换:例如 int 转换为 float,char 转换为 int,double 转换为 int 等。
  • 派生类向基类的转换:也就是向上转型,
  • const 转换:也即将非 const 类型转换为 const 类型,例如将 char * 转换为 const char *。
  • 数组或函数指针转换:如果函数形参不是引用类型,那么数组名会转换为数组指针,函数名也会转换为函数指针。
  • 用户自定的类型转换。

例如:

void func1(int n, float f);
void func2(int *arr, const char *str);
int nums[5];
char *url = "http://c.biancheng.net";
func1(12.5, 45);
func2(nums, url);

  对于 func1(),12.5 会从double转换为int,45 会从int转换为float;对于 func2(),nums 会从int [5]转换为int *,url 会从char *转换为const char *

函数模板调用时的类型转换

  对于函数模板,类型转换收到了更多的限制,仅能进行[const 转换]和[数组或函数指针转换],其他都不能应用于函数模板。

template<typename T> void func1(T a, T b);
template<typename T> void func2(T *buffer);
template<typename T> void func3(const T &stu);
template<typename T> void func4(T a);
template<typename T> void func5(T &a);

int name[20];
Student stu1("张华", 20, 96.5);  //创建一个Student类型的对象
func1(12.5, 30);  //Error
func2(name);  //name的类型从 int [20] 换转换为 int *,所以 T 的真实类型为 int
func3(stu1);  //非const转换为const,T 的真实类型为 Student
func4(name);  //name的类型从 int [20] 换转换为 int *,所以 T 的真实类型为 int *
func5(name);  //name的类型依然为 int [20],不会转换为 int *,所以 T 的真实类型为 int [20]

可以发现,当函数形参是引用类型时,数组不会转换为指针。

template<typename T> void func(T &a, T &b);

int str1[20];
int str2[10];
func(str1, str2);

  由于str1、str2的类型分别为int [20]和int [10],在函数调用过程中又不会转换为指针,所以编译器不知道应该将T实例化为int [20]还是int [10],导致调用失败

为函数模板显式地指明实参

  下面是一个实参推断失败的例子:

template<typename T1, typename T2> void func(T1 a){
    T2 b;
}
func(10);  //函数调用

func()有两个类型参数,分别是T1和T2,但是编译器只能推断出T1,不能推断出T2,调用失败

  显示指明的模板实参会按照从左到右的顺序与对应的模板参数匹配:第一个实参与第一个模板参数匹配,第二个实参与第二个模板参数匹配,只有尾部(最右)的类型参数的实参可以省略,而且前提是它们可以从传递给函数的实参中推断出来。 例如:

template<typename T1, typename T2> void func(T2 a){
    T1 b;
}
//函数调用
func<int>(10);  //省略 T2 的类型
func<int, int>(20);  //指明 T1、T2 的类型

显式的指明实参时可以应用正常的类型转换

  函数模板仅能进行[ const 转换 ]和[ 数组或函数指针转换 ]两种形式的类型转换,但是当我们显式的指明类型参数的实参时,就可以使用正常的类型转换了。例如:

template<typename T> void func(T a, T b);
func(10, 23.5);  //Error
func<float>(20, 93.7);  //Correct

  在第二种调用形式中,我们已经显式地指明了T的类型为float,编译器不会再为T的类型到底是int还是double而纠结了,所以可以从容地使用正常地类型转换了。

最后

以上就是敏感啤酒为你收集整理的C++ 函数模板的重载与实参推断函数模板的重载函数模板的实参模板实参推断过程中的类型转换为函数模板显式地指明实参显式的指明实参时可以应用正常的类型转换的全部内容,希望文章能够帮你解决C++ 函数模板的重载与实参推断函数模板的重载函数模板的实参模板实参推断过程中的类型转换为函数模板显式地指明实参显式的指明实参时可以应用正常的类型转换所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(66)

评论列表共有 0 条评论

立即
投稿
返回
顶部