为什么这个constexpr函数在gcc的不同情况下会给出不同的结果?

时间:2015-09-25 13:11:54

标签: c++ g++ c++14 constexpr

所以我有以下简单的片段:

template <typename T, size_t size>
struct SquareMatrix {
public:
    T data[size * size];
    constexpr T & operator()(const size_t row, const size_t col) noexcept {
        return data[row * size + col];
    }
};

constexpr auto generate() {
    auto result = SquareMatrix<int, 2>{};
    result(0, 0) = 1;
    result(1, 0) = 3;
    result(0, 1) = 2;
    result(1, 1) = 4;
    return result;
}

data生成的SquareMatrix<int, 2> generate()数组的预期内容为1, 2, 3, 4。然而...

constexpr auto test = generate();

int main() {
    for (size_t i = 0; i < 4; ++i) {
        std::cout << test.data[i] << std::endl;
    }
    return 0;
}

如果我使用g ++ 5.2和-std=c++14编译并运行此代码,则打印到控制台的结果奇怪地是1032

如果删除constexpr限定符,使其在运行时执行,或者我改为编写以下任何一个轻微变体:

int main() {
    constexpr auto test = generate();
    for (size_t i = 0; i < 4; ++i) {
        std::cout << test.data[i];
    }
    return 0;
}

......或......

constexpr auto generate() {
    auto result = SquareMatrix<int, 2>{};
    result(0, 0) = 1;
    result(0, 1) = 2; // this line and
    result(1, 0) = 3; // this line have been swapped
    result(1, 1) = 4;
    return result;
}

constexpr auto test = generate();

int main() {
    for (size_t i = 0; i < 4; ++i) {
        std::cout << test.data[i];
    }
    return 0;
}

...打印出预期结果1234。此外,clang ++ 3.7.0在所有情况下都会打印出预期的1234

我遇到过g ++错误,还是我错过了什么?

1 个答案:

答案 0 :(得分:7)

这看起来与gcc错误[5 regression] Constant expression factory function initializes std::array with static storage duration strangely有关,如果我们尝试使用gcc head live example,则可以正常使用。

错误报告具有以下类似示例,其中静态变量案例表现出类似问题,而自动变量案例则没有:

#include <array>
#include <cassert>

namespace /* anonymous */
{

  constexpr auto
  make_array(const int val) noexcept
  {
    std::array<int, 2> result = { { val, 0 } };
    return result;
  }

  // Replacing `constexpr` by `const` doesn't change anything.
  constexpr auto numbers_static = make_array(42);

}

int main()
{
  const auto numbers_automatic = make_array(42);
  assert(numbers_automatic[0] == 42);  // okay
  assert(numbers_static[0] == 42);     // fails
}