C++之模版详解(进阶)

目录

[1. 非类型模板参数](#1. 非类型模板参数)

[2. 类模板的特化](#2. 类模板的特化)

[2.1 函数模板特化](#2.1 函数模板特化)

[2.2 类模版特化](#2.2 类模版特化)

[3. 模板的分离编译](#3. 模板的分离编译)


**1.**非类型模板参数

模版参数有两种,一种叫类型模版参数,一种叫做非类型模版参数。今天我们来讲讲非类型模版参数。

template <int N> 中的 int N 就是典型的非类型模板参数。这里的 int 是参数的类型,而 N 是参数名,它接收的是一个具体的常量值 ,而非像普通类型模板参数(如 template <typename T>)那样接收一个 "类型"。

两者核心区别就是:

  • 类型模板参数:传递 "类型"(如 T = int
  • 非类型模板参数:传递 "常量值"(如 N = 10

简单来说就是类型模版参数是改变类型,非类型模版参数改变的是类型后面的数。
注意:
1. 浮点数、类对象以及字符串是不允许作为非类型模板参数的。
2. 非类型的模板参数必须在编译期就能确认结果。

cpp 复制代码
// 模板参数 <int N> 就是非类型参数(传递的是"值")
template <int N>  // N 是一个编译期已知的整数
class FixedArray {
private:
    int arr[N];  // 用 N 作为数组长度(编译时就确定了)
public:
    // 打印数组长度
    void printSize() {
        std::cout << "数组长度是:" << N << std::endl;
    }
};

int main() {
    // 实例化时指定具体的"值"(非类型参数)
    FixedArray<3> arr3;  // N=3,创建一个长度为3的数组
    FixedArray<5> arr5;  // N=5,创建一个长度为5的数组

    arr3.printSize();  // 输出:数组长度是:3
    arr5.printSize();  // 输出:数组长度是:5

    return 0;
}

**2.**类模板的特化

2.1 函数模板特化

模板的特化(Template Specialization)是 C++ 中为模板提供 "特殊处理" 的机制。简单说就是:当模板的参数满足某种特定条件时,我们可以为它定义一套专门的实现,而不使用通用模板的代码

比如说下面这个代码,第一个Print就是普通的模版,第二个Print就是特化的模版。我们要在函数的名字后面加上<char>说明我们要特殊处理的是char类型的。由于计算机是从上往下编译的,所以当它在mian函数里面遇到Print,同时里面是char类型的时候,它会自动匹配第二个,然后打印出对应的ASCII码。

cpp 复制代码
#include <iostream>

// 通用模板(适用于大多数类型)
template <typename T>
void Print(T value) {
    std::cout << "通用模板:" << value << std::endl;
}

// 对 char 类型的特化版本
template <>  // 特化标记:空参数列表,表示"针对特定类型"
void Print<char>(char value) {  // 明确指定特化的类型:char
    std::cout << "char 特化:字符 '" << value << "' 的 ASCII 码是 " << (int)value << std::endl;
}

int main() {
    Print(123);    // 匹配通用模板,输出:通用模板:123
    Print('A');    // 匹配 char 特化版本,输出:char 特化:字符 'A' 的 ASCII 码是 65
    return 0;
}

2.2 类模版特化

下面这个就是类模版特化中的全特化,简单来说就是给类的每一个参数都传递模版参数,就叫做全特化。

PS:如果只给一个类的部分参数传递模版参数那就是偏特化。

cpp 复制代码
#include <iostream>
#include <string>

// 通用类模板:处理任意类型的数据
template <typename T>
class DataProcessor {
public:
    void process(T data) {
        std::cout << "通用处理:" << data << "(类型未知,按默认方式处理)" << std::endl;
    }
};

// 全特化:专门处理 int 类型
template <>  // 全特化标记(空参数列表)
class DataProcessor<int> {  // 明确指定特化的类型是 int
public:
    void process(int data) {
        std::cout << "int 专用处理:" << data << "(整数翻倍后为 " << data * 2 << ")" << std::endl;
    }
};

// 全特化:专门处理 string 类型
template <>
class DataProcessor<std::string> {  // 明确指定特化的类型是 string
public:
    void process(std::string data) {
        std::cout << "string 专用处理:" << data << "(字符串长度为 " << data.size() << ")" << std::endl;
    }
};

int main() {
    // 测试通用模板(处理 double 类型,没有特化版本)
    DataProcessor<double> dProc;
    dProc.process(3.14);  // 用通用模板处理

    // 测试 int 特化版本
    DataProcessor<int> iProc;
    iProc.process(10);    // 用 int 专用处理

    // 测试 string 特化版本
    DataProcessor<std::string> sProc;
    sProc.process("hello");  // 用 string 专用处理

    return 0;
}

**3.**模板的分离编译

一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链 接起来形成单一的可执行文件的过程称为分离编译模式,比如说我写的那个boost搜索引擎项目就是分离编译模式。

这个就相当于写了一个通用的类,然后我们想用时对他进行调用。

相关推荐
Web3VentureView13 小时前
Web4的入口,即将打开 | SYNBO CLUB移动端亟待上线
大数据·人工智能·区块链·媒体·加密货币
ZHOUPUYU13 小时前
PHP 8.6的底层革命。那些看不见的优化,才是真正的惊喜
开发语言·后端·php
A-刘晨阳13 小时前
工业物联网时代时序数据库选型指南:从大数据架构视角深度解析Apache IoTDB
大数据·物联网·时序数据库·iotdb
白云如幻13 小时前
【JDBC】集合、反射和泛型复习
java·开发语言
cui_ruicheng13 小时前
C++ 数据结构:AVL树原理与实现
数据结构·c++
小龙报13 小时前
【数据结构与算法】环与相遇:链表带环问题的底层逻辑与工程实现
c语言·数据结构·c++·物联网·算法·链表·visualstudio
佩奇大王14 小时前
P2118 排列字母
java·开发语言·算法
runfarther14 小时前
Java变量作用域详解
java·开发语言
java1234_小锋14 小时前
Java高频面试题:MyBatis与JPA有哪些不同?
java·开发语言·mybatis·jpa
confiself14 小时前
A2UI实时渲染展示
开发语言·javascript·css