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 有两个模板参数(第二参数是分配器),需注意匹配

相关推荐
Flittly1 小时前
【AgentScope Java新手村系列】(2)第一个Agent-基础对话
java·spring boot·spring·ai
Kobebryant-Manba1 小时前
学习文本处理
开发语言·python
摇滚侠1 小时前
Spring MVC 不是一个单独的框架,是 Spring 框架的一个模块
java·spring·mvc
阿正的梦工坊1 小时前
【Rust】04-借用、引用与切片
java·数据库·rust
福大大架构师每日一题1 小时前
2026年6月TIOBE编程语言排行榜,Go语言排名第13,Rust语言排名12。关于Rust已进入平台期的报道似乎为时过早。
开发语言·golang·rust
无限进步_1 小时前
从零实现一个迷你Shell——深入理解Linux命令行解释器
linux·运维·服务器·开发语言·c++·chrome
拙慕JULY1 小时前
小程序返回 base64 文件报错
开发语言·javascript·小程序
月疯1 小时前
torch:expand和repeate的区别
开发语言·python·深度学习
Drone_xjw1 小时前
qt配置项目样式表
开发语言·qt