C++ 知识点22 函数模板

C++ 函数模板


一、为什么要有函数模板?

先看痛点:你要写两个交换函数,int 版、double 版:

cpp 复制代码
// int 交换
void swapInt(int &a, int &b)
{
    int t = a; a = b; b = t;
}
// double 交换
void swapDouble(double &a, double &b)
{
    double t = a; a = b; b = t;
}

逻辑完全一样 ,只是类型不一样,重复写代码太冗余。

函数模板作用 :写一份通用逻辑 ,不指定具体类型,编译器根据你传的类型,自动生成对应版本的函数

一句话:一份模板,适配所有类型


二、函数模板 标准语法

1. 模板头写法

两种写法都可以:

cpp 复制代码
template <typename T>   // 写法1:推荐
template <class T>      // 写法2:老式写法,效果一样
  • template:关键字,声明这是模板

  • <> 里面是模板参数

  • T类型参数,代表任意一种通用类型(自己起名,T/T1/T2 都行)

2. 完整函数模板格式

cpp 复制代码
template <typename T>
函数返回值 函数名(形参列表)
{
    函数逻辑,里面用 T 当类型用
}

三、写第一个函数模板:通用交换函数

cpp 复制代码
#include <iostream>
using namespace std;
​
// 定义函数模板
template <typename T>
void mySwap(T &a, T &b)
{
    T temp = a;
    a = b;
    b = temp;
}
​
int main()
{
    int x = 10, y = 20;
    mySwap(x, y);   // 自动推导 T = int
    cout << x << " " << y << endl;
​
    double m = 1.1, n = 2.2;
    mySwap(m, n);   // 自动推导 T = double
    cout << m << " " << n << endl;
​
    return 0;
}

核心关键点

  1. 你只写了一份代码

  2. 编译器在编译时,自动实例化int版double版 函数

  3. 不用自己重复写重载函数


四、函数模板的两种调用方式

1. 自动类型推导(常用)

编译器根据实参,自己猜出 T 是什么类型

cpp 复制代码
mySwap(x, y); // 自动推导出 T=int

要求:形参类型必须完全一致,不能一个 int 一个 double。

2. 显式指定类型

手动告诉编译器 T 是什么类型

cpp 复制代码
mySwap<int>(x, y);
mySwap<double>(m, n);

适用场景:

  • 无法自动推导时

  • 强制指定类型转换


五、模板支持 多个类型参数

可以定义多个通用类型 T1、T2

cpp 复制代码
template <typename T1, typename T2>
void printTwo(T1 a, T2 b)
{
    cout << a << " , " << b << endl;
}
​
// 使用
printTwo(100, 3.14);
printTwo("hello", 666);

六、普通函数 和 函数模板 同时存在(优先级规则)

  1. 如果普通函数能匹配上 :优先调用普通函数

  2. 如果普通函数匹配不上,编译器会实例化模板调用

  3. 可以用 空模板参数<> 强制调用模板函数

示例:

cpp 复制代码
// 普通函数
void mySwap(int &a, int &b)
{
    cout << "调用普通函数" << endl;
}
​
// 函数模板
template <typename T>
void mySwap(T &a, T &b)
{
    cout << "调用函数模板" << endl;
}
​
int main()
{
    int a=1,b=2;
    mySwap(a,b);        // 优先普通函数
    mySwap<>(a,b);      // 强制调用模板
    double c=1.1,d=2.2;
    mySwap(c,d);        // 只能匹配模板,调用模板
    return 0;
}

考试面试必背规则

普通函数优先匹配;模板做备胎;<> 强制走模板。


七、函数模板 具体化 / 特化(重点)

场景:大部分类型用通用模板,唯独某一个类型要单独特殊处理 ,就用模板特化

语法格式:

cpp 复制代码
// 通用模板
template <typename T>
void show(T a)
{
    cout << "通用版本:" << a << endl;
}
​
// 针对 string 类型 特化版本
template <>
void show<string>(string a)
{
    cout << "string 特化版本:" << a << endl;
}

调用规则:

匹配到特化版本 → 优先用特化;否则用通用模板。


八、函数模板 底层原理(必须理解)

  1. 模板本身不生成函数,只是一张 "图纸"

  2. 编译阶段,根据实参类型 ,按照图纸生成对应类型的函数 ,这个过程叫 模板实例化

  3. 用多少种类型,就生成多少个重载版本

  4. 只在第一次使用该类型时实例化,后续复用


九、函数模板 使用限制(易错点 必记)

  1. 自动推导时,实参类型必须严格一致
cpp 复制代码
template<typename T>
void func(T a, T b);
​
func(10, 3.14); // 报错!一个int 一个double,推导冲突

解决:显式指定 func<int>(10,3.14)

  1. 模板里不能出现无法通用的操作

    比如模板里写 T++,如果 T 是字符串、自定义类且没重载 ++,直接报错。

  2. 模板声明和实现不能拆分到 .h 和 .cpp

    因为编译时要看到完整模板代码,否则无法实例化;

    工程里模板一般全部写在头文件里

  3. 不能用局部类型、匿名类型做模板参数


十、一句话浓缩 必背考点

  1. 函数模板用 template<class T>template<typename T> 定义;

  2. 作用:一份代码适配多种数据类型,减少冗余;

  3. 调用方式:自动类型推导、显式指定类型

  4. 普通函数和模板共存:普通函数优先,<> 强制走模板

  5. 特化模板:给特定类型单独定制逻辑

  6. 原理:模板是图纸,使用时才实例化生成具体函数

  7. 模板代码建议全写在头文件,不要分离声明实现。

相关推荐
Tisfy1 小时前
LeetCode 2553.分割数组中数字的数位:模拟(maybe+翻转)——java也O(1)
java·数学·算法·leetcode·题解·模拟·取模
平行侠1 小时前
33水库抽样 - 从未知大小的流中等概率采样
数据结构·算法
求学中--1 小时前
鸿蒙网络请求从入门到精通:HttpURLConnection+第三方库,GET/POST/文件上传全覆盖
开发语言·php·harmonyos
吴声子夜歌1 小时前
Java——Integer与二进制算法
java·算法
Controller-Inversion1 小时前
42. 接雨水
数据结构·算法·leetcode
Controller-Inversion1 小时前
33. 搜索旋转排序数组
数据结构·算法·leetcode
yaodong5181 小时前
Gemini长上下文重塑RAG架构
开发语言·php
风味蘑菇干1 小时前
继承 + static + final 综合应用
java·开发语言
IT策士1 小时前
Python 面试系列:常见 100 个经典面试问题,从入门到进阶
开发语言·python·面试