You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
PR#16 compiles extremely slowly in the Windows MSVC environment #17
Activity
refactor: Update casting templates to use std_numeric for improved ty…
refactor: Update conversion module imports and simplify casting logic…
FrozenLemonTee commentedon Mar 26, 2026
排查报告
1. 问题原因概括
本次编译速度异常缓慢的根本原因,不是
conversion模块里的算法本身运行复杂,而是conversion公共 API 的模板约束发生了重叠,导致编译器在模块编译阶段反复进行高成本的 concepts / subsumption / overload ordering 判定。具体来说:
underlying::traits<T>将 builtin 数值类型纳入了underlying_type体系,因此int、uint16_t、double这类类型不仅满足std_numeric,也满足underlying_type/numeric_underlying_type。conversion::checked_cast/saturating_cast/truncating_cast/exact_cast同时提供了“builtin numeric 路径”和“underlying bridge 路径”两套公开重载。checked_cast<int>(42u)、saturating_cast<int>(NaN),两套候选同时成立,编译器需要做额外的约束归约与偏序比较。basic_conversion_tests中首先暴露;而当primitive.impl和operations.operators这两个高扇出热点模块重新接回conversion公共 API 后,实例化数量被迅速放大,最终表现为 Clang 和 Windows/MSVC 模块编译显著变慢甚至超时。2. 关键代码改动对比
2.1 问题版本:公开
castAPI 的候选集重叠旧版本中,公开
castAPI 同时存在两套可见重载:同时,builtin 类型又被注册进了
underlying::traits<T>:这意味着 builtin 类型既是
std_numeric,也是underlying_type。于是像下面这样的调用:
会同时命中两套公开模板候选,编译器必须额外判断“哪一套更受约束”。
2.2 修复版本:将 builtin 路径与 underlying 路径彻底拆开
修复后的公开 API 改成了互斥的两层:
同样的策略也应用到了
unchecked_cast、saturating_cast、truncating_cast、exact_cast。修复后的规则变成:
std_numeric路径这样一来,builtin-to-builtin 的调用不再落入两套公开候选,编译器也就不需要再做高成本的约束排序。
2.3 为什么块2 / 块3会把问题放大
primitive.impl中的convert_underlying_()是跨 underlying 构造、赋值、store、compare_exchange的公共入口,属于高扇出热点。operations.operators中的apply_assign()是+=、-=、*=、/=、位运算赋值等一整组复合赋值的公共入口,也是高扇出热点。因此,只要这两个入口重新直接调用
conversion::numeric_risk/conversion::saturating_cast,上面那组重叠约束带来的编译成本就会被全局放大。3. 后续验证结果
std_numeric与underlying_type,可以直接从以下代码看到:primitives/src/underlying/impl.cppm
Lines 9 to 14 in be07d3f
primitives/src/underlying/traits.cppm
Line 29 in be07d3f
primitives/src/underlying/traits.cppm
Lines 167 to 198 in be07d3f
primitives/src/conversion/underlying.cppm
Lines 306 to 384 in 2452fba
这里将公开
castAPI 的 builtin 路径收紧为std_numeric,并显式排除了 builtin-to-builtin 情况下走underlying_typebridge 的可能性。conversion:primitives/src/primitive/impl.cppm
Lines 59 to 69 in be07d3f
primitives/src/operations/operators.cppm
Lines 529 to 560 in be07d3f
_MSC_VER下的 smoke 分支:primitives/tests/basic/conversion/underlying/test_builtin_casts.cpp
Lines 11 to 18 in 07c4816
primitives/tests/basic/conversion/underlying/test_builtin_casts_ext.cpp
Lines 11 to 16 in 07c4816
验证结果如下:
cmake + clang下,先前会卡住的basic_conversion_tests已可正常构建并通过。xmake + msvc下,块2单独还原、块3单独还原、块2+块3同时还原,均可在 120 秒限制内完成构建并通过全部测试。Merge pull request #16 from mcpplibs/feat-explicit-conversion