C++ 模板核心内容与高频面试题汇总

本文整理自学习笔记,涵盖模板基础、特化、注意事项以及常见面试题,适合复习

一、模板基础

1.1 函数模板

cpp 复制代码
template <typename T>
T max(T a, T b) {
    return a > b ? a : b;
}
  • 编译器根据实参推导模板参数,生成具体函数(实例化)

  • 可显式指定模板参数:max<int>(1, 2)

1.2 类模板

cpp 复制代码
template <typename T>
class Stack {
    std::vector<T> data;
public:
    void push(const T& val) { data.push_back(val); }
    void pop() { data.pop_back(); }
    T& top() { return data.back(); }
};
  • 类模板的成员函数只有在使用时才会被实例化

  • 类模板不能隐式推导模板参数(C++17 起可通过构造函数推导,需显式指定)

1.3 模板参数的类型

  • 类型参数typename Tclass T

  • 非类型参数int Nsize_t N、指针、引用等(编译期常量)

  • 模板模板参数template <typename> class Container

二、模板特化

2.1 全特化

为特定类型提供完全不同的实现

cpp 复制代码
template <>
class Stack<bool> {
    // 特殊实现
};

2.2 偏特化

只限定部分模板参数(仅适用于类模板,函数模板无偏特化,可重载)

cpp 复制代码
template <typename T>
class Stack<T*> {  // 针对指针类型的偏特化
    // ...
};

2.3 函数模板重载 vs 特化

  • 函数模板不能偏特化,但可以用重载实现类似效果

  • 函数模板的全特化语法:

cpp 复制代码
template <>
const char* max<const char*>(const char* a, const char* b) { ... }

但通常推荐使用重载而非特化函数模板,因为重载解析规则更直观

三、注意事项与常见陷阱

3.1 模板的编译与分离编译

  • 模板的定义通常必须放在头文件中因为编译器在实例化时需要看到完整定义

  • 若想分离编译,可以显式实例化(.cpptemplate class Stack<int>;),但不够灵活

3.2 typename 与 class 的区别

  • 在声明模板参数时,两者等价

  • 但在依赖类型中,必须用 typename 告诉编译器这是一个类型:

cpp 复制代码
typename T::iterator it;   // 若没有 typename,编译器会认为 iterator 是静态成员

3.3 依赖名称

  • 模板中依赖模板参数的名称称为依赖名称。对于非依赖名称,编译器会在第一阶段进行查找

  • 使用 this->Base<T>:: 来限定依赖基类中的名称

  • 函数模板通常被隐式视为 inline,但这不是强制的,编译器自行决定。

四、高频面试题

Q1:函数模板与普通函数重载时,哪个优先?

A:普通函数优先。如果存在完全匹配的普通函数,则不会实例化函数模板

cpp 复制代码
void max(int, int);
template <typename T> void max(T, T);
max(1, 2);  // 调用普通函数

Q2:类模板的成员函数何时实例化?

A:只有被调用时才会实例化。这允许类模板只实现所需函数,未被使用的函数即使有错误也不会被编译 --按需实例化

Q3:typenameclass 在模板参数中有什么区别?

A :在声明模板参数时没有区别,但在依赖类型中必须用 typename,如 typename T::value_type

Q4:什么是模板的偏特化?举例说明

A :针对部分模板参数进行特化。例如 template <typename T> class Stack<T*> 是针对指针类型的偏特化----其他参数保持原来不变

Q5:如何避免模板代码膨胀?

A:将不依赖模板参数的代码抽取到非模板基类中,或将公共部分封装到普通函数中

Q6:std::enable_if 的原理是什么?

A :它基于 SFINAE。当条件为 true 时,enable_if 有一个公共成员 type,否则没有,导致模板实例化失败,从而移除候选

Q7:什么是"两阶段名称查找"?

A:模板在定义时对非依赖名称进行第一轮查找(不依赖模板参数),在实例化时对依赖名称进行第二轮查找

Q8:模板元编程是编译时还是运行时?

A:编译时。利用模板特化和递归在编译期完成计算,如计算斐波那契数列

Q9:template <template <typename> class Container> 的作用?

A :模板模板参数允许将一个模板作为参数传递,例如 Stack<int, std::vector>,但 std::vector 有两个模板参数(第二参数是分配器),需注意匹配

相关推荐
爱笑的源码基地10 分钟前
高并发 Redis 缓存门诊HIS系统源码,含财务统计药房进销存
java·程序·门诊系统·诊所系统·云诊所源码
段一凡-华北理工大学23 分钟前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化
Ljwuhe32 分钟前
C++——多态
开发语言·c++
越甲八千1 小时前
STL stack为何没有迭代器
c++
心平气和量大福大1 小时前
C#-WPF-Window主窗体
开发语言·c#·wpf
莫逸风3 小时前
【AgentScope 2.0】 0. 学习指南
java·llm·agent·agentscope
从零开始的代码生活_3 小时前
C++ 继承详解:访问控制、对象模型、菱形继承与设计取舍
开发语言·c++·后端·学习·算法
云小逸3 小时前
【C++ 第七阶段:模板、泛型编程与工程综合详解】
开发语言·c++
z123456789863 小时前
2026最新两款AI编程工具深度对比实测
java·数据库·ai编程
GIS阵地3 小时前
QgsSingleBandPseudoColorRenderer 完整详解(QGIS 3.40.13 C++)
开发语言·前端·c++·qt·qgis