zoukankan      html  css  js  c++  java
  • C++基础--函数模板

    函数模板是通用的函数描述,其使用泛型来定义函数。其实就是有些操作,如果撇开具体的变量的数据类型,其操作是一样的如果我们将这些操作写成一个模板,在调用不同变量的时候就设定好变量类型就可了,后续的操作基本都是一个流程了。

    比如我要对两个变量进行交换,那么不管是int型、double型还是long型或者类或者结构体啥的,我都可以这样实现:

    T A = AAAAA;
    T B = SB;
    T temp = A;
    A = B;
    B = tem;

    这里的T就是数据类型的,不管是什么数据类型,只要可以进行如上操作的,都可以用这个模板来做。

    1、函数模板定义

    函数模板的定义基本上固定的:

    template <typename T>    
    void aiZuoNiNa(T a)
    {
        
    }

    其中,template是函数模板的关键字,关键字typename是声明该函数模板的泛型类型,可以用class来替代(C++98前没有typename,所以用class),这两个关键字和尖括号是必须的,typename之后的T可以任意写,只要符合C++命名规则即可,很多人会写做T。

    需要注意的是,在定义函数模板的时候是不会创建任何函数的,只是在告诉编译器在调用模板函数的时候该如何定义函数并调用,也就是说如果定义了模板函数,但是从未调用过的话,是不会生成相应的函数的,在程序中使用了定义好的函数模板,那么编译器将检查使用的参数类型,然后根据类型来生成相应函数(就如同我们手写了一个函数一样)。所以即使定义函数模板只有一份,如果调用了两次且数据变量不同的话,编译器会生成两份独立的函数在可执行程序中,也就是说函数模板不会缩短可执行程序,最终的可执行程序也不会包含函数模板,但是会包含调用两次函数模板后编译器所生成的两个独立的函数。

    函数模板一般是放在头文件中的。

    并不是模板函数的所有参数都得是泛型,可以不要泛型,或者包含其它类型:

    template <typename T>
    void aiZuoNiNa(T a)
    {
    
    }
    
    template <typename T>
    void aiZuoNiNa(T a, int b)
    {
    
    }
    
    template <typename T>
    void aiZuoNiNa()
    {
    
    }

    2、模板重载

    上面一个例子涉及到函数模板的重载,函数模板的重载与普通函数重载一样,重载函数模板的时候,需要满足函数名相同、参数列表不同函数重载特点即可。

    3、函数模板的局限性

    这个要怎么说呢,应该说是某些情况不适合简单抽象化或者简单模板化,才导致了函数模板的局限性,比如比较两个变量的大小,对于int、float等数据类型可以实现模板化,但是如果是一个结构体或者一个类、或者一个数组等,在不重载比较操作符号(<、>、==)的时候显然不能这样比较吧。

    4、显式具体化

    因为有些情况可能不能直接简单的用函数模板,所以才会提供一个具体化函数定义(称为显式具体化,explicit specialization),其中包含所需要的代码,在编译器找到与调用函数匹配的具体化定义后就不再寻找模板函数了。也就是显示具体化函数优先级大于函数模板。C++98的具体化方法规定:

    1、对于给定的函数名,可以有非模板函数、模板函数、显示具体化模板函数以及它们的重载;

    2、显式具体化的原型和定义应以template<>开头,并通过名称来指定类型;

    3、具体化优先于常规模板,而非模板函数优先于具体化和常规模板。

    第一条有重载的意味,第二条指出显示具体化的格式,第三条指出当存在多个函数的时候,编译器寻找顺序是非模板函数>具体化模板函数>模板函数。在调用模板函数指定数据类型的时候编译器是会生成一个对应的函数实例,这个函数是不在代码中可见的,故而这种实例化是隐式的,而显示具体化则是在代码里定义的:

    // 函数模板
    template <typename T>
    void jiaoJiRen(T a, T b)
    {
    
    }
    //显式具体化
    template<> void jiaoJiRen<char>(char a, char b)
    {
    
    }

    5、实例化和具体化

    一开始是只有隐式实例化,显示实例化是现在的C++才有的,显式实例化需要声明所需的数据类型(用<>指示数据类型),并在声明前面添加关键字template:

    template void jiaoJiRen(int a, int b);

    显式具体化是要求编译器在调用的时候不要按照函数模板中的方式来生成函数定义,而要用显式具体化的函数:

    //方式一
    template<> void jiaoJiRen<char>(char a, char b)
    {
    
    }
    //方式二
    template<> void jiaoJiRen(char a, char b)
    {
    
    }

    显式具体化和显式实例化的区别:

    1、具体化函数声明前

    2、显式具体化除了声明还有函数定义,显式实例化只需要做函数声明即可。

    3、在同个文件(或者转换单元)中使用同一种类型的显示实例化和显式具体化会出错。

    函数模板这一块大致就记录这一些,我觉得暂时够用即可,毕竟是一个工具,目前就是挖的很深,没有使用的余地的话,很快就遗忘,个人的一点感受,之前看设计模式的时候觉得都记住了,一段时间后都模糊了,然后自己昨天写完一个小软件的时候才意识到自己其实用到了单例模式,再去查下单例模式,才知道我用的这个叫懒汉方式。所以有点感想,对于工具的一种学习方法是在实践中使用它,故而有句很装逼的话:


    无他,但手熟尔。

    上善若水,为而不争。
  • 相关阅读:
    [转]java中的匿名内部类总结
    linux 命令总结
    [转载]nohub java -jar xx.jar >/dev/null 2>&1 &
    Java正则表达式Pattern和Matcher类详解
    spark基础知识介绍(包含foreachPartition写入mysql)
    spark 运行架构
    spark核心原理
    行动操作
    控制操作
    键值转换操作
  • 原文地址:https://www.cnblogs.com/Bearoom/p/11721755.html
Copyright © 2011-2022 走看看