模板元编程之函数模板(一)

一、概述

函数模板提供了一种函数行为,该函数行为可以用多种不同的类型进行调用,换句话说函数模板代表一个函数家族,它的表示看起来和普通的函数很相似,唯一的区别就是有些函数元素是未确定的,这些元素将在使用时被参数化。

下面是一个返回两个值中最大者的函数模板

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

这个模板定义了一个“返回两个值中最大者”的函数家族,两个值是通过函数参数a和b传递给该函数模板的;而参数的类型还没确定,用模板参数T来代替。

模板参数必须用如下形式的语法来声明:

template <用逗号隔开的参数列表>

在上面的程序中,类型参数是T,可以使用任何标识符作为类型参数的名称,但使用T已经成为了一种惯例,类型参数T表示的是,调用者调用这个函数时所指定的任意类型,可以使用任何类型(基本类型,类等)来实例化该类型参数,只要所用类型提供模板使用的操作就可以,例如上面的这个例子,类型T需要支持operator<,因为a和b就是使用这个运算符来比较大小的。

二、函数模板

1.1 模板的使用

复制代码
#include <iostream>

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

int main() {
    int a = 110, b = 200;
    std::cout << "Max_Func(a, b):" << Max_Func(a, b) << std::endl;

    double d1 = 1.5, d2 = 3.8;
    std::cout << "Max_Func(d1, d2):" << Max_Func(d1, d2) << std::endl;

    std::string s1 = "abcdefg", s2 = "abc";
    std::cout << "Max_Func(s1, s2):" << Max_Func(s1, s2) << std::endl;
    
    return 0;
}
复制代码

打印结果:

 2.2 实参的推导

当我们为某些实参调用一个诸如Max_Func()的模板时,模板参数可以由我们所传递的实参来决定的,如果我们传递了两个int给参数类型T const&,那么编译器能够得出结论:T必须是int,注意,这里不允许进行自动类型转换,每一个T都必须正确的匹配,如:

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

Max_Func(3, 8); //OK:两个实参的类型都是int
Max_Func(4, 4.9); // ERROR:第一个T是int,而第二个T是double

下面方法可以解决上面的错误,可以显示指定(或者限定)T的类型

Max_Func<double>(a, d1);

2.3 模板参数

函数模板有两种类型的参数:

(1).模板参数:位于函数模板名称的前面,有一对尖括号内部进行声明:

template <typename T>  //T是模板参数

(2).使用参数:位于函数模板名称之后,在一对圆括号内部进行声明:

Max_Func(T const& a, T const& b) //a和b是调用参数

当模板参数和调用参数没有发生关联,或者不能通过调用参数来决定模板参数的时候,你在调用的时候就必须显示指定模板参数:

emplate <typename T> 
inline T const& Max_Func(T const& a, T const& b) 
...
Max_Func<double>(3, 3.5) //用double来实例化T
    

另外也可以引入第三个模板实参类型,来定义函数模板的返回类型:

template <typename T1, typename T2, typename RT>
inline RT Max_Func(T1 const& a, T2 const& b)

但是模板实参的推导并不适合返回类型,因为RT不会出现在函数调用参数的类型里面,因此函数调用并不能推导出RT,所以必须显示的指定模板实参列表:

Max_Func<int, double, double>(2, 2.2)

上面的例子也可以改变模板参数的声明顺序,在调用时指定返回类型:

template <typename RT, typename T1, typename T2>
inline RT Max_Func(T1 const& a, T2 const& b)
...
Max_Func<double>(3. 3.8) //返回类型是double

在这个示例中,调用Max_Func<double>时显示的把RT指定为doule,其他两个参数T1和T2可以根据调用实参分别演绎为int和double.

2.4 重载函数模板

和普通函数一样,函数模板也可以被重载,相同的函数名称可以具有不同的函数定义,于是,当使用函数名称进行函数调用的时候,C++编译器必须决定要调用哪个函数。

重载函数模板示例:

复制代码
/* 求两个int的最大值 */
inline int const& Max_Func(int const& a, int const& b) {
    std::cout << "调用非模板函数" << std::endl;
    
    return a < b ? b : a;
}

/* 求两个任意类型值中的最大值 */
template <typename T> 
inline T const& Max_Func(T const& a, T const& b) {
    std::cout << "调用两个参数的模板函数" << std::endl;

    return a < b ? b : a;
}

/* 求三个任意类型值中的最大值 */
template <typename T>
inline T const& Max_Func(T const& a, T const& b, T const& c) {
    std::cout << "调用三个参数的模板函数" << std::endl;
    
    T d = a < b ? b : a;
    return d < c ? c : d;
}

int main() {
    Max_Func(6, 21, 4); //调用具有3个参数的模板
    Max_Func(7.0, 23.0); //调用Max_Func<double>
    Max_Func(10, 30); //调用int重载的非模板参数
    Max_Func<>(19, 29); //Max_Func<int>(通过实参演绎)
    Max_Func('a', 25.5); //调用int重载的非模板函数
    Max_Func('a', 'b'); //调用Max_Func<char>(通过实参演绎)
    
    return 0;
}
复制代码

打印结果:

 如上述例子所示。一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数,对于非模板函数和同名的函数模板,如果其他条件都是相同的话,那么在调用的时候,重载解析过程通常会调用非模板函数,而不会该模板产生出一个实例。

 

posted @   TechNomad  阅读(55)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示