MSVC 2017单翻译单元内静态初始化顺序是否违反C++17标准?
MSVC 2017的这个行为确实违反了C++17标准
嘿,这个问题我之前也碰到过,你的代码逻辑完全符合C++17规范,MSVC的输出明显是不符合标准的bug。
为什么说这违反了标准?
根据C++17关于inline变量初始化的规则(对应cppreference提到的「部分有序动态初始化」):
- 部分有序动态初始化适用于所有未隐式或显式实例化特化的inline变量。若在每个翻译单元中,部分有序变量V定义于有序或部分有序变量W之前,则V的初始化先于W的初始化(若程序启动线程则为先行发生关系)
你的代码里,TC::values的定义明确在A、B、C之前,按照标准,values数组必须在这三个引用变量之前完成初始化。这意味着A、B、C绑定的必然是values数组里的对应元素,地址比较结果应该全为true——就像GCC和Clang的输出那样。
MSVC出问题的可能原因
你提到移除_value成员后MSVC就正常了,这说明编译器在处理带有非平凡成员的constexpr类的inline变量时,初始化顺序的逻辑出了问题。当类包含const int这样的成员时,MSVC可能错误地让A、B、C的初始化提前,或者没有正确保证values的初始化优先级,导致引用绑定到了错误的内存位置(比如临时对象),这才会出现地址不相等的情况。
可行的解决/规避办法
- 升级MSVC版本:这个bug在MSVC 2019及以后的版本中已经被修复了,升级编译器是最直接的解决方式。
- 用constexpr函数替代引用成员:如果暂时没法升级,可以把
A、B、C改成返回constexpr引用的静态函数,比如:
函数调用的初始化顺序规则更明确,能绕开MSVC的这个bug。static constexpr TC const& A() { return values[0U]; } static constexpr TC const& B() { return values[1U]; } static constexpr TC const& C() { return values[2U]; }
内容的提问来源于stack exchange,提问作者monkey0506
相关产品推荐
相关产品推荐

