C++面试周刊(6):constexpr、内联函数、编译期元编程
文章目录
各位老师好!
这是CPP面试冲刺周刊 (c++ weekly) 陪你一起快速冲击大厂面试 第7期
周刊目标:
- 不是成为C++专家,而是成为C++面试专家
本期内容:
- constexpr、内联函数、编译期元编程
常见误区(反常识):
- const 修饰变量 分配内存空间吗?什么时候分配,什么时候不分配
一、背景与初衷:为什么 C++11 引入 constexpr
1. 过去的问题:#define
、const
、inline
的局限
-
#define
宏常量:不参与类型检查,调试困难。 -
const
变量:虽然安全,但在 C++11 之前,const
不保证编译期常量。 -
inline
函数:通过内联展开减少函数调用开销,但依然在 运行期计算。
我们会遇到这种场景:
|
|
因为 NODE_NUM
不是编译期常量,buf
的大小无法在编译期确定,编译错误。
C++11 引入
constexpr
,让我们可以在 编译期完成计算,避免运行时开销。
C++11 引入 constexpr
的初衷
C++11 引入了 constexpr
,目标是:
-
让 常量表达式在 编译期完成求值;
-
提高 性能,减少运行期不必要的计算;
-
统一常量语义,避免编译器行为不一致。
改写上面的例子:
constexpr int NODE_NUM = 3; char buf[NODE_NUM]; // ✅ 编译期直接展开
编译器会在 编译期直接把 NODE_NUM
计算成 3,
生成的汇编里,buf
是一个 固定大小的栈数组,根本不会在运行期再算一次。
二、技术优势与劣势
特性 | inline |
const / constexpr |
编译期元编程(模板 + constexpr ) |
---|---|---|---|
目标 | 减少函数调用开销 | 固定值、优化常量表达式 | 利用编译期完成复杂逻辑 |
性能 | 消除调用栈,但仍然运行期求值 | const 多为运行期,constexpr 编译期计算 |
完全避免运行期开销 |
适用场景 | 高频调用的短函数 | 常量定义、查表、状态切换 | 哈希计算、调度策略、数据映射表 |
缺点 | 代码膨胀、编译时间增加 | constexpr 在 C++11 较受限,C++14 才支持更复杂逻辑 |
编译时间长、代码可读性差 |
3fs:代码
static constexpr size_t kNodeIdKeyedMapExpectedNumElements = 1000;
constexpr int kNumIovecs = 64;
std::array<iovec, kNumIovecs> iovecs;
constexpr uint32_t kInvalidatedFlag = 1u « 0u; // Bit 0
constexpr uint32_t kReadAvailableFlag = 1u « 1u; // Bit 1
constexpr uint32_t kReadNewWakedFlag = 1u « 2u; // Bit 2
constexpr uint32_t kWriteAvailableFlag = 1u « 3u; // Bit 3
constexpr uint32_t kWriteNewWakedFlag = 1u « 4u; // Bit 4
constexpr uint32_t kWriteHasMsgFlag = 1u « 5u; // Bit 5
constexpr uint32_t kWriteNewMsgFlag = 1u « 6u; // Bit 6
constexpr uint32_t kLastReadFinished = 1u « 7u; // Bit 7
constexpr uint32_t kLastWriteFinished = 1u « 8u; // Bit 8
三、适用场景
在分布式存储和数据库的高性能项目中,constexpr
和编译期元编程适用于 大量重复计算 的场景:
-
哈希值计算
Ceph 的 PG 映射里会用到哈希:1 2 3 4
constexpr uint32_t hash(const char* s, size_t n) { return n ? (hash(s, n-1) * 131 + s[n-1]) : 0; } constexpr auto key = hash("pool1", 5);
- 收益:hash 在编译期算完,运行期不消耗 CPU。
-
常量查表
比如 TiDB 的执行计划优化:1
constexpr std::array<int, 4> priorities = {1, 2, 4, 8};
- 收益:常量表编译期固化,避免 runtime 初始化。
-
模板 +
constexpr
的高性能策略调度1 2 3 4 5
template <typename Strategy> constexpr auto choose_strategy() { if constexpr (std::is_same_v<Strategy, SSD>) return "low-latency"; else return "high-throughput"; }
- 收益:调度策略完全在 编译期分发,零运行时分支判断。
四、底层原理
constexpr
的本质是 把一部分运行期逻辑前移到编译期,核心是:
-
语法约束
C++11 要求constexpr
函数必须:-
单个
return
表达式 -
不允许循环和复杂控制流
-
不允许动态分配内存
→ C++14 以后放宽限制,可以写递归、if-else 等复杂逻辑。
-
-
编译器行为
-
如果输入是编译期常量 → 在编译期计算结果,直接写死到目标代码。
-
如果输入是运行时值 → 退化为普通函数,在运行期执行。
-
-
示例:编译器直接展开常量
1 2
constexpr int square(int x) { return x * x; } int a = square(3);
编译器会直接把
a
展开为:1 2
mov eax, 9 mov [a], eax
没有函数调用,也没有乘法指令。
五、与模板元编程结合:C++17/20 的 constexpr 进化
在 C++17 和 C++20,constexpr
与 模板元编程 深度结合,让我们能写出接近函数式语言的代码:
|
|
-
C++17 的
if constexpr
让模板分支只保留必要的代码,消除了未使用分支的编译错误。 -
C++20 的
consteval
更进一步,强制 编译期求值,让性能更加可控。
六、总结与实践建议
技术 | 用途 | 收益 | 注意事项 |
---|---|---|---|
inline |
展开函数,消除调用开销 | 小幅提升性能 | 代码膨胀 |
constexpr |
编译期计算 | 避免运行期重复计算,零开销 | C++11 受限,C++14+ 更强大 |
模板 + constexpr |
编译期分发策略 | 极致性能优化 | 编译时间、可读性 |
实践建议
高频小函数:优先
constexpr
大型查表、哈希:
constexpr
+std::array
策略分发:
if constexpr
+ 模板性能敏感核心逻辑:结合
consteval
强制编译期求值
面试准备心得
曾经有一个让我心跳加速的岗位放在我面前,
我没有珍惜。
等到别人拿到 offer 的那一刻,
我才追悔莫及!
人世间,最痛苦的事情,
不是没钱吃饭,
也不是没房没车,
而是——错过了那个能让我逆天改命的机会!
如果上天再给我一次机会,
我一定会对那个岗位说三个字:
“我要你!”
如果非要在这份“心动”上加一个期限,
一万年太久了……
我只想要——21天!
你可能面临两种选择
① 犹豫不前:准备到天荒地老
“这个岗位太难了,我先准备一下吧。”
于是你准备1天、1周、1个月、1年……
等再回头,3年就这样过去了。
- 每天忙着搬砖,没时间系统复习
- 每次想起要准备,又感觉心里没底
- 面试知识点更新太快,拿着旧地图找新机会 最后,错过了一次又一次心动的岗位。
② 盲目回答:机会就在眼前,却抓不住
终于等来一场面试,
你觉得问题很简单,张口就答,
结果用“几千元思维”回答“百万年薪岗位”。
- 面试官问到C++底层实现,答不上来
- 设计题说到高并发架构,没实战经验
- 一紧张,连项目里真实做过的东西都讲不清
一次面试失利,也许就意味着和理想岗位失之交臂。
更残酷的是
在你犹豫的这几年里,
找工作的成本越来越高:
- 一个部门、一个领导,可能坚持一年就被解散
- 一个项目,可能在10年、20年后,
曾经复杂的业务规则、先进的架构,早已被淘汰 - 市场上新的技术和面试要求,每年都在不断升级
等你回过头来,发现不仅机会没了,
连准备的方向都变了。
不是让你成为C++专家, 而是让你成为C++面试专家。
不是让你疯狂学习新知识, 而是帮你重新整理已有知识,
让你的能力与面试题精准对齐。
因为,21天就够了,
足够让我火力全开,
- 一边补齐 C++ 知识点,
- 一边刷爆经典面试题,
- 一边撸穿开源项目,
- 让自己变得不可替代!
核心方法论:
让你学到每个 c++知识,都关联一个经典面试,并对对应开源项目实践
-
系统备战
每天 20~30 分钟,聚焦 C++ 核心知识,
三周时间完成高效梳理。 -
经典面试题
每个知识点都关联一个高频面试题,
让你知道“为什么考”和“怎么答”。 -
开源项目实践
通过真实项目理解底层原理,
不背答案,而是用实践打动面试官。 -
场景驱动学习
还原真实面试场景,
帮你学会“怎么说服面试官”。 -
三周后,面对面试官,你能自信说出:
*“问吧,准备好了。”
最动人的作品,为自己而写,刚刚好打动别人
1️⃣ 如果有更多疑问,联系小王,一起交流,进步
2️⃣ 关注公众号:后端开发成长指南(回复"面经"获取)获取过去我全部面试录音和面试复盘。
抬头看天:走暗路、耕瘦田、进窄门、见微光
- 不要给自己这样假设:别人完成就等着自己完成了,大家都在一个集团,一个公司,分工不同,不,这个懒惰表现,这个逃避问题表现。
- 别人不这么假设,至少本月绩效上不会写成自己的,至少晋升不是你,裁员淘汰就是你。
- 目标:在跨越最后一道坎,拿百万年薪,进大厂。