模板不是零成本:你的 std::variant<20 types> 在编译期生成了 400 个 visit 实例,链接器在帮你删它们

📅 2026/6/30 7:30:23
模板不是零成本:你的 std::variant<20 types> 在编译期生成了 400 个 visit 实例,链接器在帮你删它们
一个不该慢下来的链接步骤,慢了。那是一个中等规模的 C++ 服务,三十多万行,链接阶段从十几秒爬到了一分半。perf看不出名堂,因为瓶颈不在运行时——它在ld。第一反应是查那些最常见的元凶:是不是谁加了个肥依赖?是不是 debug 构建的目标文件漏进了 release 链接?是不是某个静态库被链了两遍?逐个排掉,都不是——依赖列表没动,构建类型干净,库也没重复。链接命令行和半年前几乎一字不差,可它就是慢了、产物就是大了。变量只剩一个:这半年的代码改动本身。把可执行文件丢进bloaty,.text段比半年前大了快一倍,而这半年我们几乎没加什么新功能,只是把一组散落的if-else类型分发重构成了std::variant+std::visit。看起来更现代、更类型安全、还号称"零开销抽象"。我用nm -C --size-sort把符号按大小倒排,翻到一半就明白了。满屏的std::__detail::__variant::__gen_vtable_impl...::__visit_invoke,一个接一个,类型参数长到换行。它们大多是 weak symbol,前面挂着W。再用readelf -g看 section group,几百个 COMDAT 组,签名全是这些 visit 实例的 mangled name。链接器没出 bug。它在干一件每天都在干、但这次量