zoukankan      html  css  js  c++  java
  • 函数模板与模板函数

    1.函数指针——指针函数 

    函数指针的重点是指针。表示的是一个指针,它指向的是一个函数,例子: 

    int   (*pf)(); 

    指针函数的重点是函数。表示的是一个函数,它的返回值是指针。例子: 

    int*   fun(); 

    2.数组指针——指针数组 

    数组指针的重点是指针。表示的是一个指针,它指向的是一个数组,例子: 

    int   (*pa)[8]; 

    指针数组的重点是数组。表示的是一个数组,它包含的元素是指针。例子; 

    int*   ap[8]; 

    3.类模板——模板类(class   template——template   class) 

    类模板的重点是模板。表示的是一个模板,专门用于产生类的模子。例子: 

    template   <typename   T> 

    class   Vector 



                … 

    }; 

    使用这个Vector模板就可以产生很多的class(类),Vector <int> 、Vector <char> 、Vector <   Vector <int>   > 、Vector <Shape*> ……。 

    模板类的重点是类。表示的是由一个模板生成而来的类。例子: 

    上面的Vector <int> 、Vector <char> 、……全是模板类。 

    这两个词很容易混淆,我看到很多文章都将其用错,甚至一些英文文章也是这样。将他们区分开是很重要的,你也就可以理解为什么在定义模板的头文件.h时,模板的成员函数实现也必须写在头文件.h中,而不能像普通的类(class)那样,class的声明(declaration)写在.h文件中,class的定义(definition)写在.cpp文件中。

    array是一个模板,array<int, 50>是一个模板实例 - 一个类型。从array创建array<int, 50>的过程就是实例化过程。实例化要素体现在main.cpp文件中。如果按照传统方式,编译器在array.h文件中看到了模板的声明,但没有模板的定义,这样编译器就不能创建类型array<int, 50>。但这时并不出错,因为编译器认为模板定义在其它文件中,就把问题留给链接程序处理。

    现在,编译array.cpp时会发生什么问题呢?编译器可以解析模板定义并检查语法,但不能生成成员函数的代码。它无法生成代码,因为要生成代码,需要知道模板参数,即需要一个类型,而不是模板本身。

    这样,链接程序在main.cpp 或 array.cpp中都找不到array<int, 50>的定义,于是报出无定义成员的错误。


    关于一个缺省模板参数的例子: 

    template   <typename   T   =   int> 

    class   Array 



                … 

    }; 

    第一次我定义这个模板并使用它的时候,是这样用的: 

    Array   books;//我认为有缺省模板参数,这就相当于Array <int>   books 

    上面的用法是错误的,编译不会通过,原因是Array不是一个类。正确的用法是Array <>   books; 

    这里Array <> 就是一个用于缺省模板参数的类模板所生成的一个具体类。 

    4.函数模板——模板函数(function   template——template   function) 

    函数模板的重点是模板。表示的是一个模板,专门用来生产函数。例子: 

    template   <typename   T> 

    void   fun(T   a) 



                … 



    在运用的时候,可以显式(explicitly)生产模板函数,fun <int> 、fun <double> 、fun <Shape*> ……。 

    也可以在使用的过程中由编译器进行模板参数推导,帮你隐式(implicitly)生成。 

    fun(6);//隐式生成fun <int> 

    fun(8.9);//隐式生成fun <double> 

    fun(‘a’);//   隐式生成fun <char> 

    Shape*   ps   =   new   Cirlcle; 

    fun(ps);//隐式生成fun <Shape*> 

    模板函数的重点是函数。表示的是由一个模板生成而来的函数。例子: 

    上面显式(explicitly)或者隐式(implicitly)生成的fun <int> 、fun <Shape*> ……都是模板函数。 

    模板本身的使用是很受限制的,一般来说,它们就只是一个产生类和函数的模子。除此之外,运用的领域非常少了,所以不可能有什么模板指针存在的,即指向模板的指针,这是因为在C++中,模板就是一个代码的代码生产工具,在最终的代码中,根本就没有模板本身存在,只有模板具现出来的具体类和具体函数的代码存在。 

    提醒:在本文的几个术语中,语言的重心在后面,前面的词是作为形容词使用的。 

    2 函数模板的异常处理

    函数模板中的模板形参可实例化为各种类型,但当实例化模板形参的各模板实参之间不完全一致时,就可能发生错误,如:

    复制代码
    template<typename T>       
    void min(T &x, T &y)
    {  return (x<y)?x:y;  }
    
    void func(int i, char j)
    {
       min(i, i);
       min(j, j);
    
       min(i, j);   
       min(j, i);
    }
    复制代码

    例子中的后两个调用是错误的,出现错误的原因是,在调用时,编译器按最先遇到的实参的类型隐含地生成一个模板函数,并用它对所有模板函数进行一致性检查,例如对语句

    min(i, j);

    先遇到的实参i是整型的,编译器就将模板形参解释为整型,此后出现的模板实参j不能解释为整型而产生错误,模板函数是没有隐含的类型转换功能的。解决此种异常的方法有两种:

    ⑴采用强制类型转换,如将语句min(i, j);改写为min(i,int( j));

    ⑵用非模板函数重载函数模板

    方法有两种:

    ① 借用函数模板的函数体

    此时只声明非模板函数的原型,它的函数体借用函数模板的函数体。如改写上面的例子如下:

    复制代码
    template<typename T>       
    void min(T &x, T &y)
    {  return (x<y)?x:y;  }
    
    int min(int,int);
    
    void func(int i, char j)
    {
       min(i, i);
       min(j, j);
    
       min(i, j);
       min(j, i);
    }
    复制代码

    执行该程序就不会出错了,因为重载函数支持数据间的隐式类型转换。

    ② 重新定义函数体

    就像一般的重载函数一样,重新定义一个完整的非模板函数,它所带的参数可以随意。

    C++中,函数模板与同名的非模板函数重载时,应遵循下列调用原则:

    • 寻找一个参数完全匹配的函数,若找到就调用它。若参数完全匹配的函数多于一个,则这个调用是一个错误的调用。

    • 寻找一个函数模板,若找到就将其实例化生成一个匹配的模板函数并调用它。

    • 若上面两条都失败,则使用函数重载的方法,通过类型转换产生参数匹配,若找到就调用它。

    •若上面三条都失败,还没有找都匹配的函数,则这个调用是一个错误的调用。

    3.函数模板与类模板有什么区别?

    答:函数模板的实例化是由编译程序在处理函数调用时自动完成的,而类模板的实例化必须由程序员在程序中显式地指定。

         即函数模板允许隐式调用和显式调用而类模板只能显示调用

  • 相关阅读:
    关于返回上一页功能
    Mybatis Update statement Date null
    SQLite reset password
    Bootstrap Validator使用特性,动态(Dynamic)添加的input的验证问题
    Eclipse使用Maven2的一次环境清理记录
    Server Tomcat v7.0 Server at localhost failed to start
    PowerShell一例
    Server Tomcat v7.0 Server at libra failed to start
    商标注册英语
    A glance for agile method
  • 原文地址:https://www.cnblogs.com/zhaodun/p/6400934.html
Copyright © 2011-2022 走看看