nvc++编译C++20 constexpr代码报常量值错误的原因及修复方案
问题根因
nvc++ 22.5版本存在C20 constexpr特性的实现缺陷,未正确支持标准允许的constexpr上下文操作:
按照C20标准,constexpr函数中允许先默认初始化平凡类型(如std::array这类聚合POD类型)局部变量,在完成所有成员的赋值后再返回该对象,该行为完全合法。GCC 9+、Clang 10+均已正确实现该规则,因此可以正常编译你的代码。
但22.5版本的nvc常量求值器没有覆盖该场景,错误判定已经完成全元素赋值的result对象存在未初始化访问,因此抛出编译错误。该问题和操作系统版本、C标准编译参数无关,属于编译器本身的bug,因此在Ubuntu 20.04环境、切换-std=c++2a/-std=c++20参数都会复现相同错误。
可行修复方案
优先推荐无副作用、兼容所有编译器的修改方式,其余方案可根据实际场景选择:
- 方案1(推荐):对局部数组做零初始化,绕过编译器的未初始化检测
将make_array函数中result的定义从:
修改为:std::array<std::array<double, 7>, 5> result;
仅添加一对空大括号完成值初始化,不会改变原有逻辑,也不会增加编译期/运行时开销,修改后g++、clang++、nvc++22.5均可正常编译运行,输出结果符合预期。std::array<std::array<double, 7>, 5> result{}; - 方案2:升级nvc版本
23.1及之后版本的nvc已经修复了该constexpr实现bug,无需修改源码即可正常编译。 - 方案3:放弃该变量的编译期求值(不推荐)
如果必须使用22.5版本nvc++且无法修改初始化逻辑,可以去掉constexpr修饰将const_array改为运行期初始化,但会失去编译期计算的收益,仅作为兜底方案。
验证说明:采用方案1修改后的代码,执行
nvc++ -std=c++20 test.cxx -o test && ./test可正常输出结果2,与g++、clang++的运行结果完全一致。
内容的提问来源于stack exchange,提问作者Andreas Rupp
相关产品推荐
相关产品推荐

