首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >C++面试周刊(6):constexpr、内联函数、编译期元编程

C++面试周刊(6):constexpr、内联函数、编译期元编程

作者头像
早起的鸟儿有虫吃
发布2025-10-10 12:05:51
发布2025-10-10 12:05:51
13500
代码可运行
举报
运行总次数:0
代码可运行

各位老师好!

这是CPP面试冲刺周刊 (c++ weekly) 陪你一起快速冲击大厂面试 第7期

周刊目标

不是成为C++专家,而是成为C++面试专家

本期内容

constexpr、内联函数、编译期元编程

常见误区(反常识):

const 修饰变量 分配内存空间吗?什么时候分配,什么时候不分配

一、背景与初衷:为什么 C++11 引入 constexpr

1. 过去的问题:#defineconstinline 的局限

#define 宏常量:不参与类型检查,调试困难。

const 变量:虽然安全,但在 C++11 之前,const不保证编译期常量

inline 函数:通过内联展开减少函数调用开销,但依然在 运行期计算

我们会遇到这种场景:

代码语言:javascript
代码运行次数:0
运行
复制
const int NODE_NUM = 3; //在 C++98 中只是一个 运行期常量,不是 编译期常量。
char buf[NODE_NUM]; // 编译直接报错

因为 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 和编译期元编程适用于 大量重复计算 的场景:

1

哈希值计算 Ceph 的 PG 映射里会用到哈希:

代码语言:javascript
代码运行次数:0
运行
复制
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。

2

常量查表 比如 TiDB 的执行计划优化:

代码语言:javascript
代码运行次数:0
运行
复制
constexpr std::array<int, 4> priorities = {1, 2, 4, 8};

收益:常量表编译期固化,避免 runtime 初始化。

3

模板 + constexpr 的高性能策略调度

代码语言:javascript
代码运行次数:0
运行
复制
template <typename Strategy>
constexpr auto choose_strategy() {
    if constexpr (std::is_same_v<Strategy, SSD>) return "low-latency";
    else return "high-throughput";
}

收益:调度策略完全在 编译期分发,零运行时分支判断。


四、底层原理

constexpr 的本质是 把一部分运行期逻辑前移到编译期,核心是:

1

语法约束 C++11 要求 constexpr 函数必须:

单个 return 表达式

不允许循环和复杂控制流

不允许动态分配内存 → C++14 以后放宽限制,可以写递归、if-else 等复杂逻辑。

2

编译器行为

如果输入是编译期常量 → 在编译期计算结果,直接写死到目标代码。

如果输入是运行时值 → 退化为普通函数,在运行期执行。

3

示例:编译器直接展开常量

代码语言:javascript
代码运行次数:0
运行
复制
constexpr int square(int x) { return x * x; }
int a = square(3);

编译器会直接把 a 展开为:

代码语言:javascript
代码运行次数:0
运行
复制
mov eax, 9
mov [a], eax

没有函数调用,也没有乘法指令


五、与模板元编程结合:C++17/20 的 constexpr 进化

在 C++17 和 C++20,constexpr模板元编程 深度结合,让我们能写出接近函数式语言的代码:

代码语言:javascript
代码运行次数:0
运行
复制
template <typename T>
constexpr size_t type_id() {
    if constexpr (std::is_same_v<T, int>) return 1;
    else if constexpr (std::is_same_v<T, double>) return 2;
    else return 0;
}
代码语言:javascript
代码运行次数:0
运行
复制

C++17if constexpr 让模板分支只保留必要的代码,消除了未使用分支的编译错误。

C++20consteval 更进一步,强制 编译期求值,让性能更加可控。


六、总结与实践建议

技术

用途

收益

注意事项

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++ 核心知识, 三周时间完成高效梳理。

经典面试题 每个知识点都关联一个高频面试题, 让你知道“为什么考”和“怎么答”。

开源项目实践 通过真实项目理解底层原理, 不背答案,而是用实践打动面试官

场景驱动学习 还原真实面试场景, 帮你学会“怎么说服面试官”。

三周后,面对面试官,你能自信说出: *“问吧,准备好了。”

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-08-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 后端开发成长指南 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、背景与初衷:为什么 C++11 引入 constexpr
    • 1. 过去的问题:#define、const、inline 的局限
  • C++11 引入 constexpr 的初衷
  • 二、技术优势与劣势
  • 三、适用场景
  • 四、底层原理
  • 五、与模板元编程结合:C++17/20 的 constexpr 进化
  • 六、总结与实践建议
  • 面试准备心得
    • ① 犹豫不前:准备到天荒地老
    • ② 盲目回答:机会就在眼前,却抓不住
    • 更残酷的是
    • 核心方法论:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档