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. 模板代码建议全写在头文件,不要分离声明实现。

相关推荐
地平线开发者5 小时前
profiler debug 工具用法与高一致性策略
算法·自动驾驶
编程大师哥5 小时前
匿名函数 lambda + 高阶函数
java·python·算法
isyangli_blog5 小时前
OpenDayLight (Carbon 版本) 启动与组件安装
开发语言·php
vb2008115 小时前
FastAPI APIRouter
开发语言·python
Benszen5 小时前
KVM虚拟化解决方案
开发语言·perl
会编程的土豆5 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
東雪木5 小时前
多线程与并发编程 专属复习笔记
java·开发语言·笔记·java面试
我叫袁小陌5 小时前
算法解题思路指南
算法
MC皮蛋侠客5 小时前
C++17 多线程系列(五):C++17 并行算法——从串行到并行的零成本迁移
c++·多线程
地平线开发者5 小时前
Conv+BN+Add+ReLU 融合机制简介
算法·自动驾驶