我有以下代码,在gcc和clang上的行为与预期相同。但是,MSVC给了我一个意想不到的结果。
让我们先看一下有问题的代码。
#include <iostream>
// -----------------------------------------------
class Test // Dummy for MCVE
{
public:
Test();
void Print();
private:
int arr[5];
};
Test tst;
// -----------------------------------------------
template<typename T>
struct range // some stuff not needed by example removed
{
constexpr range(T n) : b(0), e(n) {}
constexpr range(T b, T e) : b(b), e(e) {}
struct iterator
{
T operator*() { return i; }
iterator& operator++() { ++i; return *this; }
bool operator!=(iterator other) { return i != other.i ; }
T i;
};
iterator begin() const { return{ b }; }
iterator end() const { return{ e }; }
private:
T b,e;
};
constexpr range<int> coord(5);
// -----------------------------------------------
Test::Test()
{
for(auto i : coord)
arr[i]=i;
}
void Test::Print()
{
for(auto i : coord)
std::cout << arr[i] << std::endl;
}
// -----------------------------------------------
int main()
{
tst.Print();
}
现在,在clang和gcc上都打印'0 1 2 3 4'
但是,在MSVC上,这会打印'0 0 0 0 0'
原因是当全局变量tst
上的构造函数
运行,'coord'尚未初始化(至0,5),但它也不是随机的,而是(0,0)。
对我来说,constexpr
初始化在常规初始化之前发生是有意义的。 MSVC是否符合此行为?
我应该注意到我正在使用MSVC版本14.0.22823.1,并且 通过改变顺序可以获得预期的结果 声明
答案 0 :(得分:5)
对于静态存储持续时间,对象初始化必须按以下顺序进行:
constexpr
)。相关标准,
C ++14§3.6.2/ 2:“具有静态存储持续时间(3.7.1)或线程存储持续时间(3.7.2)的变量应为零初始化(8.5) 在进行任何其他初始化之前。 [...] 执行常量初始化:[...]如果具有静态或线程存储持续时间的对象由构造函数调用初始化,并且如果 初始化full-expression是对象的常量初始值设定项; [...]一起,零初始化和常量初始化称为静态初始化;所有其他初始化都是动态初始化。在进行任何动态初始化之前,应执行静态初始化。
同一段定义(打破文本流,所以我将其删除)
“对象
o
的常量初始化程序是一个表达式,它是一个常量表达式,除了它还可以调用constexpr
构造函数对于o
及其子对象,即使这些对象是非文字类类型。
在我使用Visual C ++ 2015验证的报告示例中,静态存储持续时间对象tst
的动态初始化发生在静态存储持续时间对象coord
的常量初始化之前,这是一个编译器错误。