【C++】模板(一)——函数模板

定义函数模板

模板的引入,使得类型可以作为参数出现。函数模板相比于普通的函数,它可以为多种不同的类型所调用,具体的类型只有在被调用时才会被确定。

template <typename T>
T const& max(T const& a, T const& b)
{
	return (a > b)? a : b;
}

在上面的程序中,尖括号中使用关键字typename引入类型参数T。T只是一种标识符,可以用任何其他符合命名规则的标识符代替。可以在调用函数时,指定类型(基本类型、类等)。

也可引入多个类型参数,在尖括号中使用逗号隔开。

template <typename T, typename F, ...>
re-type func(parameters){func-body}

关键字typename也可以换成class,其作用一致,在历史上刚开始就是使用class,但为避免与类定义混淆,便引入typename。

函数模板实例化

下面对模板函数进行多次调用:

max(12, 34);				//返回34
max(12.1, 3.2);				//返回12.1
std::string a = "template";
std::string b = "class";
max(a, b);	//返回template

在模板函数被调用时,编译器会对它进行自发的实例化,即用具体参数的类型替换掉定义模板函数时使用的类型参数T。

在没有指定用于替换的类型时,编译器会检查传入实参的类型,推断出用于实例化的类型,这被称为实参演绎

当然也可以显式的指定实例化类型:

max<double>(12, 12.1);

检查到非指定类型的参数时,编译器会调用强制类型转换,使其能够比较。但如果不指定,对于传入的两个不同的参数类型,则会报错。

指定返回类型

这是一个小技巧:对于上面的代码,若模板函数接收到两个不同类型的参数时,我们经常无法判断具体的返回类型,也难以提前指定,可以使用三个类型参数来解决这一问题。

template <typename Rt, typename T1, typename T2>
Rt max(T1 const& a, T2 const& a)
{
	return a > b ?a : b;
}

注意声明三个不同类型参数的顺序,下面对这个模板函数进行调用:

max<double>(12, 12.1);

首先,后两个不同的类型参数,可以避免使用一个类型参数时,传入不同类型的参数会报错的问题;而第一个类型参数用于在函数中指定返回值类型。

返回值类型声明在最前面,调用时就可只指定返回值类型,后两个类型参数则根据实参演绎确定。

注意返回值不可使用引用,因为可能返回的是经过类型转换产生的临时变量。

重载函数模板

重载函数模板与重载普通函数类似,下面的实例解释了编译器在何种情况下会选择调用何种函数(普通函数还是模板函数):

#include <iostream>
#include <string>

inline int const &max(int const &a, int const &b)
{
    std::cout << "1st Called" << std::endl;
    return a > b ? a : b;
}

inline char *const &max(char *const &a, char *const &b)
{
    std::cout << "2nd Called" << std::endl;
    return *a > *b ? a : b;
}

template <typename T>
inline T const &max(T const &a, T const &b)
{
    std::cout << "3th Called" << std::endl;
    return a > b ? a : b;
}

template <typename T>
inline T const &max(T const &a, T const &b, T const &c)
{
    std::cout << "4th Called" << std::endl;
    return max(max(a, b), c);
}

int main()
{
    std::cout << ::max(12, 2) << std::endl;   // 1st Called    12
    std::cout << ::max(1, 2, 3) << std::endl; // 4th Called    1st Called  1st Called  3
    std::cout << ::max<>(1, 2) << std::endl;  // 3th Called    2
    std::string a = "template", b = "class";
    std::cout << ::max(a, b) << std::endl; // 3th Called    template
    char c[]{"template"}, d[]{"class"};
    std::cout << ::max(c, d) << std::endl; // 2nd Called    template
}

对于模板函数通过实例化可以实现,但普通函数已定义,编译器会优先调用普通类型的函数,但可以通过列出一个空的类型参数列表表示强制调用模板函数(对比主函数中的第一和第三个输出)。

需要注意的是,实例中第四个重载(三个参数的比较)必须放置在其他重载声明的后面,因为其内部调用了其他的重载函数。至少有一个重载的声明需要放置在这个函数前面,才能通过编译。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值