19 C++ 模板-函数模板

模板——函数模板


C++模板的基础用法主要包括函数模板和类模板两大核心机制。

一、函数模板的语法定义

1. 函数模板通用语法

函数模板:

template<class/typename 类型形参1, ...>
返回类型 函数模板名 (形参表) {...}

2. 函数模板特化语法

函数模板特化: 把函数模板单独实例出一个特定版本。
函数模板的特化版本,不需要定义模板参数,直接template<>。

template<>
返回类型 函数模板名<类型实参1, ...> (形参表) {...}

二、函数模板

  1. 定义方式
    使用 template<typename T>template<class T> 声明模板,T 为虚拟类型参数:

    template<typename T>
    T max(T a, T b) { return a > b ? a : b; }
    

    通过类型参数泛化,支持多种类型的参数。

  2. 实例化方式

    • 隐式实例化:编译器根据传入参数自动推导类型,如 max(3, 5) 推导为 int 类型。
    • 显式实例化:手动指定类型,如 max<double>(3.5, 5.0)
  3. 非类型参数
    模板参数可以是固定值(如常量整数),但只能是整型、枚举或指针类型:

    template<typename T, int size>
    void printArr(T (&arr)[size]) { /*...*/ }
    

    常用于数组操作或容器大小设定。

  4. 注意事项

    • 普通函数优先级高于模板函数,若两者均可匹配,优先调用普通函数。
    • 模板不支持自动类型转换(如 intdouble),普通函数支持。

三、函数模板的通用应用示例

1. 用类型模板实现泛型函数

  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;
     }
    

    适用于所有支持拷贝构造和赋值操作的类型,如intdouble或自定义类。

  2. 比较或计算函数
    如求最大值、最小值或数组遍历操作:

     #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. 函数模板显式实例化

  1. 显式指定类型
    避免隐式推导错误,直接指定模板实例化类型:

    头文件(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;
     }
     
    

四、函数模板的特化应用示例

为所有模板参数提供具体类型或值的特化形式。

  1. 语法规范

    • 特化必须声明在原始模板之后。
    • 显式使用template<>前缀声明特化版本。
    • 函数模版只支持全特化。
  2. 优先匹配规则

    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;
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值