模板元编程之函数模板(一)
一、概述
函数模板提供了一种函数行为,该函数行为可以用多种不同的类型进行调用,换句话说函数模板代表一个函数家族,它的表示看起来和普通的函数很相似,唯一的区别就是有些函数元素是未确定的,这些元素将在使用时被参数化。
下面是一个返回两个值中最大者的函数模板
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; }
打印结果:
如上述例子所示。一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数,对于非模板函数和同名的函数模板,如果其他条件都是相同的话,那么在调用的时候,重载解析过程通常会调用非模板函数,而不会该模板产生出一个实例。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?