当年我们做库。
很少有人一开始就想清楚边界。
通常是先能跑。
然后头文件越长越像结绳。
最后谁也不敢动。
当年:头文件里什么都放
你写个 util.h。
工具函数全塞进去。
到后面。
它会 include 一堆别的头。
而别的头又 include 它。
你就得到一个环。
编译器当然能处理。
但你的心智模型会坏掉。
线上啪一下:我只改了一个私有函数,结果所有人都重编译
你改了一行实现。
结果 CI 编译从 2 分钟变 20 分钟。
你不服。
但现实就是。
头文件里塞了太多实现细节。
任何改动都会触发全量重编。
用模块写一个小库:先把“外面能看到的”挑出来
假设你有一个小库。
对外只暴露两个函数。
hash64 和 to_hex。
module interface:只 export 你真的要承诺的东西
export module util;
export unsigned long long hash64(const char* s);
export const char* to_hex(unsigned long long x);
这一段就是对外合同。
你以后想重构内部。
只要这个合同不变。
用你库的人就不用改。
module implementation:实现可以随便重写
module util;
unsigned long long hash64(const char* s) {
unsigned long long h = 1469598103934665603ull;
for (; *s; ++s) h = (h ^ (unsigned char)(*s)) * 1099511628211ull;
return h;
}
const char* to_hex(unsigned long long) {
return "...";
}
注意这里是 module util;。
不是 export module util;。
它说明这是实现单元。
外面看不到实现细节。
使用方:import 就够了
import util;
int main() {
auto h = hash64("abc");
(void)to_hex(h);
}
使用方不再关心。
你内部 include 了哪些头。
也不再被你内部宏污染。
关键结论
模块实战最重要的一步。
是把“合同”先写出来。
小结
先拿一个小库练手。
你会很快体会到。
export 少一点。
未来就自由一点。