C++基础-模板(template)-1

226 阅读4分钟

1. 模板基础概念

(1) 什么是模板?

模板是 C++ 泛型编程的核心,允许编写与类型无关的代码,编译器在编译时根据具体类型生成对应版本。
核心目标:避免重复代码,提高复用性。


(2) 确定参数模板(Fixed Template)

  • 语法:使用固定数量的类型参数。
    template<typename T>          // 单个类型参数
    T max(T a, T b) { return (a > b) ? a : b; }
    
    template<typename K, typename V>  // 多个类型参数
    class Pair { K key; V value; };
    
  • 特点
    • 参数数量固定(如 std::vector<T>)。
    • 适用于已知参数数量的场景。

(3) 可变参数模板(Variadic Template)

  • 语法:使用 ... 表示任意数量的类型参数。
    template<typename... Args>    // Args 是模板参数包
    void print(Args... args);     // args 是函数参数包
    
  • 特点
    • 处理不定数量参数(如 std::tuple<Args...>)。
    • 常配合递归或折叠表达式展开参数包。

参数模板(Variadic Templates)详解


2. 主模板(Primary Template)

(1) 定义

主模板是模板的默认实现,提供通用逻辑,后续可通过特化定制行为。
关键点

  • 必须先声明主模板,才能特化。
  • 可以是空实现(如 std::tuple 的主模板仅为声明)。

(2) 作用

  • 提供默认行为:通用逻辑(如 std::vector<T> 的动态数组实现)。
  • 支持特化扩展:作为全特化/部分特化的基础。
  • 递归终止条件:可变参数模板中标记递归结束(如 Tuple<>)。

(3) 示例

// 主模板(通用版本)
template<typename T>
struct Box { T value; };

// 可变参数主模板(通常为空)
template<typename... Args>
struct Tuple {};

主模板(Primary Template)的由来与用途分析


3. 实例化(Instantiation)

(1) 定义

编译器根据模板生成具体类型代码的过程。

  • 隐式实例化:通过代码调用自动触发(如 std::vector<int>)。
  • 显式实例化:手动指定类型生成代码(如 template class std::vector<int>;)。

(2) 过程

template<typename T>
T add(T a, T b) { return a + b; }

int sum = add(3, 5);  // 隐式实例化 add<int>

编译器生成:

int add<int>(int a, int b) { return a + b; }

显式实例化 vs 隐式实例化:从模板到可执行文件的完整过程


4. 特化(Specialization)

(1) 定义

为特定类型定制模板行为,覆盖主模板的默认实现。
分类

  • 全特化:完全指定所有模板参数(函数/类模板均支持)。
  • 部分特化:仅指定部分参数(仅类模板支持)。

(2) 为什么需要特化?

  • 优化性能:为特定类型(如 const char*)提供高效实现。
  • 修正行为:处理主模板不支持的场景(如指针类型)。
  • 递归终止:可变参数模板的基准情形。

(3) 示例

全特化

template<>
const char* max<const char*>(const char* a, const char* b) {
    return strcmp(a, b) > 0 ? a : b;  // 定制字符串比较
}

部分特化(类模板)

template<typename T>
class Box<T*> {  // 针对指针类型的部分特化
    T* ptr;
};

5. 面试常见问题

(1) 基础问题

  1. 模板的作用是什么?

    • 实现泛型编程,避免重复代码,提高类型安全性。
  2. 函数模板和类模板的区别?

    • 函数模板生成函数,类模板生成类;函数不支持部分特化。
  3. typenameclass 在模板中的区别?

    • 在模板参数中完全等价,但 typename 还可用于声明嵌套类型。

(2) 高级问题

  1. 什么是 SFINAE?如何利用它?
    • “Substitution Failure Is Not An Error”:模板替换失败时跳过而非报错,常用于条件编译(如 std::enable_if)。

SFINAE

  1. 可变参数模板如何实现递归展开?

    • 通过递归调用 + 基准情形(如 Tuple<>),或 C++17 的折叠表达式。
  2. 如何避免模板代码膨胀?

    • 使用显式实例化、共同基类提取代码,或 extern template 声明。

(3) 实战问题

  1. 写一个 std::tuple 的简化实现

    • 需展示主模板、递归特化、基准情形。
  2. 为什么 std::vector<bool> 是特化的?

    • 优化空间(用位存储),但导致代理迭代器问题。
  3. 解释 template<> 的作用

    • 标记全特化,表示“完全指定模板参数,无需泛型逻辑”。

总结

概念核心要点
模板基础泛型编程,支持确定参数和可变参数。
主模板默认实现,支持特化扩展,可变参数中用于递归终止。
实例化编译器生成具体代码(隐式/显式)。
特化定制特定类型行为(全特化/部分特化),解决默认实现的不足。
面试重点SFINAE、可变参数展开、代码优化、std::vector<bool> 特化问题等。

掌握模板机制是 C++ 高级开发的必备技能,理解其底层原理能显著提升代码设计能力!