C++ constexpr初始化是否应在其他初始化之前进行

C++ constexpr初始化是否应在其他初始化之前进行,c++,C++,我有下面一段代码,它在gcc和clang上的行为与预期的一样。然而,MSVC给了我一个意想不到的结果 让我们先看看有问题的代码 #include <iostream> // ----------------------------------------------- class Test // Dummy for MCVE { public: Test(); void Print(); private: int arr[5]; }; Test tst;

我有下面一段代码,它在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();
}
#包括
// -----------------------------------------------
类测试//用于MCVE的虚拟
{
公众:
Test();
作废打印();
私人:
int-arr[5];
};
测试tst;
// -----------------------------------------------
模板
struct range//删除了示例不需要的一些内容
{
constexpr范围(tn):b(0),e(n){}
constexpr范围(tb,te):b(b),e(e){}
结构迭代器
{
T运算符*(){return i;}
迭代器和运算符++(){++i;返回*this;}
布尔运算符!=(迭代器其他){返回i!=other.i;}
TⅠ;
};
迭代器begin()常量{return{b};}
迭代器end()常量{return{e};}
私人:
tb,e;
};
康斯特普山脉坐标(5);
// -----------------------------------------------
Test::Test()
{
用于(自动i:coord)
arr[i]=i;
}
无效测试::打印()
{
用于(自动i:coord)

std::cout对于静态存储持续时间对象,必须按以下顺序进行初始化:

  • 零初始化
  • 常量初始化(即
    constexpr
  • 动态初始化
  • 相关标准见

    C++14§3.6.2/2: 具有静态存储持续时间(3.7.1)或线程存储持续时间(3.7.2)的变量应初始化为零(8.5) 在进行任何其他初始化之前。[…]执行常量初始化:[…]如果构造函数调用初始化了具有静态或线程存储持续时间的对象,并且 初始化完整表达式是对象的常量初始化器;[…]零初始化和常量初始化一起称为静态初始化;所有其他初始化都是动态初始化。静态初始化应在任何动态初始化发生之前执行

    同一段定义了(打破了文本流,因此我在上面删除了它)

    对象
    o
    的常量初始值设定项是一个常量表达式,但它也可以调用
    o
    及其子对象的
    constexpr
    构造函数,即使这些对象是非文字类类型



    在已用Visual C++ 2015验证的示例中,静态存储持续时间对象<代码> TST COORD < /COD>”的常数初始化之前,这是编译器错误。可以在编译时计算,这样的计算类型是安全的。对象声明的COSTEXPR在编译时评估它们的初始值;它们基本上是保存在编译器表中的值,如果需要的话,只会发射到生成的代码中。这似乎与标准所说的不同。@ RSAHU:我看不出冲突。一个静态变量

    int const x=3
    。它可以用作原始数组大小,因此它在编译时非常重要。尽管如此,如果取该变量的地址,查看内存内容,最好在那里有一个
    3
    。它必须在加载程序后的某个时间和执行检查之前放置在那里ng语句。关于初始化的标准是关于每种初始化发生的确切时间。这现在是有意义的。感谢您的澄清。在OP的用例中,由于
    范围
    对象
    坐标
    用于进行函数调用,因此它也需要在运行时初始化。注意,t这里的规则有。虽然这并没有真正改变这是一个错误。这个编译器错误在VS 2015更新3(cl.exe版本19.00.24213.1,VS版本14.0.25425.01)中被修复