模板——函数模板
文章目录
C++模板的基础用法主要包括函数模板和类模板两大核心机制。
一、函数模板的语法定义
1. 函数模板通用语法
函数模板:
template<class/typename 类型形参1, ...>
返回类型 函数模板名 (形参表) {...}
2. 函数模板特化语法
函数模板特化: 把函数模板单独实例出一个特定版本。
函数模板的特化版本,不需要定义模板参数,直接template<>。
template<>
返回类型 函数模板名<类型实参1, ...> (形参表) {...}
二、函数模板
-
定义方式
使用template<typename T>
或template<class T>
声明模板,T
为虚拟类型参数:template<typename T> T max(T a, T b) { return a > b ? a : b; }
通过类型参数泛化,支持多种类型的参数。
-
实例化方式
- 隐式实例化:编译器根据传入参数自动推导类型,如
max(3, 5)
推导为int
类型。 - 显式实例化:手动指定类型,如
max<double>(3.5, 5.0)
。
- 隐式实例化:编译器根据传入参数自动推导类型,如
-
非类型参数
模板参数可以是固定值(如常量整数),但只能是整型、枚举或指针类型:template<typename T, int size> void printArr(T (&arr)[size]) { /*...*/ }
常用于数组操作或容器大小设定。
-
注意事项
- 普通函数优先级高于模板函数,若两者均可匹配,优先调用普通函数。
- 模板不支持自动类型转换(如
int
转double
),普通函数支持。
三、函数模板的通用应用示例
1. 用类型模板实现泛型函数
-
通用数据交换
通过类型参数T
实现任意类型的交换操作:#include <iostream> using namespace std; template<typename T> //T 为虚拟类型 void Swap(T& a, T& b) { T t = a; a = b; b = t; } int main (void) { int a =2,b=3; Swap(a,b); cout<<a<<","<<b<<endl;//3,2 char a1 ='3',b1='4'; Swap(a1,b1); cout<<a1<<","<<b1<<endl;//4,3 float a3 =4.2,b3=5.2; Swap(a3,b3); cout<<a3<<","<<b3<<endl;//5.2,4.2 return 0; }
适用于所有支持拷贝构造和赋值操作的类型,如
int
、double
或自定义类。 -
比较或计算函数
如求最大值、最小值或数组遍历操作:#include <iostream> using namespace std; template<typename T> //T 为虚拟类型 T max(T a, T b) { return a > b ? a : b; } int main (void) { int a =2,b=3; cout<<std::max(a,b)<<endl;//3 char a1 ='3',b1='4'; cout<<std::max(a1,b1)<<endl;//4 float a2 =4.2,b2=5.2; cout<<std::max(a2,b2)<<endl;//5.2 return 0; }
要求类型支持比较运算符。
2. 非类型模板参数
模板的参数可以固定值参数(或者是常量表达式)
模板参数可以是整型常量或指针,用于动态控制函数行为:
如下示例: typename T
是类型参数,int size
是非类型参数
template<typename T, int size>
void printArray(T (&arr)[size]) { /*...*/ }
常用于数组操作或编译时确定容器大小。
以下示例,用来自动推导数组元素类型 T 和数组长度 size,避免数组退化为指针时丢失长度信息
#include <iostream>
#include <typeinfo>
using namespace std;
template<typename T, int size>
void printArray(T (&arr)[size])
{
std::cout << "类型: " << typeid(T).name() <<",个数:"<<size << std::endl;
}
int main (void)
{
int arr[] ={0,1,2,3,4};
printArray(arr);
float arr1[] ={0.01,0.1,0.2,0.3,0.4};
printArray(arr1);
double arr2[] ={0.8,0.6,0.7};
printArray(arr2);
return 0;
}
输出:
类型: i,个数:5
类型: f,个数:4
类型: d,个数:3
3. 多类型参数模板
多泛型类型支持
允许定义多个类型参数,处理不同类型组合:
template<typename T1, typename T2>
auto add(T1 a, T2 b) -> decltype(a + b) { return a + b; }
模板有两个参数,类型分别是T1,T2。
示例:
#include <iostream>
#include <typeinfo>
using namespace std;
template<typename T1, typename T2>
auto add(T1 a, T2 b) -> decltype(a + b) { return a + b; }
int main (void)
{
cout<<add(2, 3)<<endl;
cout<<add(4.2, 5)<<endl;
cout<<add(2, 'A')<<endl;
int a=10; double b=1.1234;
cout<<add(a, b)<<endl;
return 0;
}
输出:
5
9.2
67
11.1234
4. 函数模板重载
与普通函数重载
当普通函数和模板函数同时存在时,编译器优先匹配普通函数:
void add(int& a, int& b); // 普通函数
template<typename T> void add(T& a, T& b); // 模板函数
#include <iostream>
#include <typeinfo>
using namespace std;
int add (int a, int b)
{
printf("1: ");
return a+b;
}
template<typename T1, typename T2>
auto add(T1 a, T2 b)
{
printf("2: ");
return a+b;
}
int main (void)
{
cout<<add(2, 3)<<endl;
cout<<add(4.2, 5)<<endl;
cout<<add(2, 'A')<<endl;
cout<<add<>(1, 2)<<endl;//强制调用模板版本
return 0;
}
输出:
1: 5
2: 9.2
2: 67
2: 3
若需强制调用模板版本,可使用空模板参数列表:Swap<>(a, b)
。
5. 函数模板显式实例化
-
显式指定类型
避免隐式推导错误,直接指定模板实例化类型:头文件(hpp)
// 泛型加法模板(支持任意数值类型) template<typename T> T add(T a, T b) { printf("template: \t"); return a + b; } // 显式实例化声明(告诉编译器在其他文件中已有实现) extern template double add<double>(double, double);
源文件(cpp)
#include <iostream> #include "temp.hpp" using namespace std; double add (double a, double b) { printf("double: \t"); return a+b; } int main (void) { cout<<add(2, 3)<<endl;//template: 5 cout<<add(4.2, 5)<<endl;//double: 9.2 cout<<add(2, 'A')<<endl;//double: 67 cout<<add(1, 2)<<endl; //template: 3 //cout<<add("hello", "world")<<endl; // error: invalid operands of types return 0; }
四、函数模板的特化应用示例
为所有模板参数提供具体类型或值的特化形式。
-
语法规范
- 特化必须声明在原始模板之后。
- 显式使用template<>前缀声明特化版本。
- 函数模版只支持全特化。
-
优先匹配规则
template <typename T> void func(T) {} // #1 template <> void func(int*) {} // #2 void func(int*) {} // #3
调用
func(new int)
时,优先级顺序为#3 > #2 > #1
。#include <iostream> #include <string> using namespace std; // 原始普通函数(处理 int 类型) int add(int a, int b) { return a + b; } // 通用模板函数(适用于大部分类型) template<class T1, class T2> auto add(T1 a, T2 b) -> decltype(a + b) { return a + b; } // 特化版本:针对 std::string 类型的加法(注意模板语法) template<> string add<string, string>(string a, string b) { return a + b; } int main() { // 测试 int 版本 cout << add(3, 5) << endl; // 输出 8 // 测试通用模板版本(混合类型) cout << add(2.5, 3) << endl; // 输出 5.5(double + int) // 测试 std::string 特化版本 cout << add(string("hello"), string("world")) << endl; // 输出 helloworld // 合法:模板推导为 <string, const char*> // 自动调用通用模板 cout << add(string("hello"), " world") << endl; // 输出 hello world return 0; }