前言

函数模板是函数的抽象,它与普通函数相似,唯一的区别就是函数参数的类型是不确定的,函数参数的类型只有在调用过程中才被确定。

这里简单记录一下方便自己查阅和回顾。

主要涉及typenametemplateclass等关键字

正文

函数模板

函数模板语法格式:

template<typename 类型占位符>  
返回值类型 函数名(参数列表) 
{ 
    //函数体; 
} 
  1. template是声明模板的关键字,<>中的参数称为模板参数

    template<typename T>
    T Add(T a) {
        return ++a;
    }
  2. typename关键字用于标识模板参数,可以用class关键字代替typename,class和typename并没有区别

    template<class T>
    T Add(T a) {
        return ++a;
    }
  3. 模板参数不能为空,一个函数模板中可以有多个模板参数,模板参数和普通函数参数相似。

template<typename type>
type Max(type a, type b) {
    if (a > b) {
        return a;
    }
    else {
        return b;
    }
}

type表示数据类型,比如可以为int,float,double等,这样就不必创建太多类型的函数了。

这里以Max模板函数为例。

// int 
int max = Max(100, 200);
std::cout << max << std::endl;

// float
float maxFloat = Max(100.1f, 808.0f);
std::cout << maxFloat << std::endl;

上面使用< double >和< float >就是防止类型转换,表示强制性类型为<>内的。

函数模板并不是一个函数,它相当于一个模子,定义一次即可使用不同类型的参数来调用该函数模板,这样做可以减少代码的书写,提高代码的复用性和效率。

隐式实例化

隐式实例化是根据函数调用时传入的参数的数据类型确定模板参数T的类型,模板参数的类型是隐式确定的。

int max = Max(100, 200);
float maxFloat = Max(100.1f, 808.0f);

这种就是隐式实例化。默认分别为int和float。

但是,这种隐式实例化方式有个不好的地方,比如第二个参数传入为不带.f的(会被识别出为int类型),编译器就有有提示:没有与参数列表匹配的 重载函数 实例参数类型为: (float, int)

// 下面写法无法通过编译
//float maxFloat = Max(100.1f, 808);

显式实例化

隐式实例化有上面问题,因此就出现显式实例化的方式。

以上面为了,改为如下后就可以正常编译。

float maxFloat = Max<float>(100.1f, 808);
float maxFloat = Max<float>(100.1, 808);

模板函数重载

这个跟函数重载一样的道理。相同的函数名,参数类型或参数个数不一样。

下面只是简单展示,具体可以看函数重载那部分。

template<typename type>
type Max(type a, type b) {
    if (a > b) {
        return a;
    }
    else {
        return b;
    }
}

template<typename type>
type Max(type a, type b, type c) {
    if (a > b ) {
        if (a > c) {
            return a;
        }
        else {
            return c;
        }
    }
    else {
        if (b > c) {
            return b;
        }
        else {
            return c;
        }
    }
}

只是随便写一下,具体参考函数重载来看。

注意事项

  1. <>中的每一个类型参数在函数模板参数列表中必须至少使用一次

    #include <iostream>
    template<typename type1, typename type2>
    type1 Max(type1 a, type1 b) {
        if (a > b) {
            return a;
        }
        else {
            return b;
        }
    }
    
    int main() {
        int max = Max<int,double>(100, 200);
        std::cout << max << std::endl;
        return 0;
    }

    上面只使用了type1,不过,使用时需要使用显示实例化。

  2. 全局作用域中声明的与模板参数同名的对象、函数或类型,在函数模板中将被隐藏。

    int num = 201;
    template<typename T>
    void func(T t)
    {
        T num = t;
        std::cout << num << std::endl;    //输出的是局部变量num,全局int类型的num被屏蔽 
    }

    在函数体内访问的num是T类型的变量num,而不是全局int类型的变量num。

  3. 函数模板中声明的对象或类型不能与模板参数同名。

    template<typename T>
    void func(T t)
    {
        //错误,定义的类型与模板参数名相同 
        typedef float T;
        T number = 100.0f;
        std::cout << number << std::endl;
    }

    我这VS可以编译过,也没有报错,但这种写法很容忍费解。。。。

    不推荐这种写法!!!

  4. 模板参数名在同一模板参数列表中只能使用一次,但可在多个函数模板声明或定义之间重复使用。

    template<typename type, typename type>
    type Max(type a, type b) {
        //略
    }

    上面错误,定义了两个type参数,这这个不能相同,下面的OK

    template<typename type1, typename type2>
    type1 Max(type1 a, type2 b) {
        //略
    }
  5. 如果函数模板有多个模板参数,则每个模板参数前都必须使用关键字class或typename修饰。

    下面是错误的

    template<typename type1, type2>
    type1 Max(type1 a, type2 b) {
        //略
    }

    正确的。typename或class不可省略。

    template<typename type1, typename type2>
    type1 Max(type1 a, type2 b) {
        //略
    }

参考文章

  1. C++程序设计教程(第二版)》

相关文章

暂无评论

none
暂无评论...