MSVC工具集143中带consteval构造函数成员的指定初始化器编译错误
指定初始化器调用consteval构造函数的编译差异问题
现象复现
以下代码在Clang 18、GCC 14中可正常编译,但在MSVC工具集143下编译失败:
struct ConstEval { consteval ConstEval(int x) : a{ x } {} int a; }; struct HasConstEval { ConstEval ceval; }; int main() { HasConstEval x{ .ceval = 1 }; }
MSVC报错指向指定初始化器行:
error C7595: 'ConstEval::ConstEval': call to immediate function is not a constant expression
但如果给HasConstEval添加构造函数并直接调用(移除指定初始化器),MSVC则能正常编译。
标准规定分析
根据C++20及后续标准,聚合初始化(包括使用指定初始化器的场景)中,成员的初始化操作只要满足初始化表达式是常量表达式,且consteval构造函数的调用符合常量表达式要求,就允许在编译期完成。
这里.ceval = 1的本质是用常量1初始化ConstEval成员,调用其consteval构造函数——这个调用完全符合常量表达式的要求:输入是编译期常量,构造过程无副作用,没有违反consteval函数的调用限制。因此标准层面这段代码是合法的。
结论:MSVC编译器实现缺陷
这是MSVC的编译器bug,而非C++标准的规定问题:
- MSVC在处理聚合类型的指定初始化器时,未能正确识别
consteval构造函数的调用处于常量表达式上下文,错误地判定该调用不是常量表达式,从而触发C7595错误。 - 当给
HasConstEval添加显式构造函数后,构造函数内部对ConstEval构造函数的调用,MSVC能正确识别为编译期可完成的操作,因此编译通过。
临时解决方案
- 给
HasConstEval添加显式构造函数:
struct HasConstEval { ConstEval ceval; constexpr HasConstEval(int val) : ceval{val} {} }; int main() { HasConstEval x{1}; }
- 在指定初始化器中显式调用构造函数(绕过MSVC的识别缺陷):
int main() { HasConstEval x{ .ceval = ConstEval{1} }; }
内容的提问来源于stack exchange,提问作者Mohammed Li
相关产品推荐
相关产品推荐

