constexpr初始化应该在其他初始化之前发生

时间:2015-07-17 04:08:39

标签: c++

我有以下代码,在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,并且 通过改变顺序可以获得预期的结果 声明

1 个答案:

答案 0 :(得分:5)

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

  1. 零初始化。
  2. 常量初始化(即constexpr)。
  3. 动态初始化。
  4. 相关标准,

    C ++14§3.6.2/ 2:
      

    具有静态存储持续时间(3.7.1)或线程存储持续时间(3.7.2)的变量应为零初始化(8.5)   在进行任何其他初始化之前。 [...] 执行常量初始化:[...]如果具有静态或线程存储持续时间的对象由构造函数调用初始化,并且如果   初始化full-expression是对象的常量初始值设定项; [...]一起,零初始化和常量初始化称为静态初始化;所有其他初始化都是动态初始化。在进行任何动态初始化之前,应执行静态初始化。

    同一段定义(打破文本流,所以我将其删除)

      

    对象o常量初始化程序是一个表达式,它是一个常量表达式,除了它还可以调用constexpr构造函数对于o及其子对象,即使这些对象是非文字类类型。

    在我使用Visual C ++ 2015验证的报告示例中,静态存储持续时间对象tst的动态初始化发生在静态存储持续时间对象coord的常量初始化之前,这是一个编译器错误。