Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this constexpr function giving different results under different circumstances in gcc?

So I have the following simple snippet:

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;
}

The expected contents of the data array in the SquareMatrix<int, 2> produced by generate() is 1, 2, 3, 4. However...

constexpr auto test = generate();

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

If I compile and run this code using g++ 5.2 and -std=c++14, the result that is printed to the console is, bizarrely, 1032.

If remove the constexpr qualifiers so it executes at runtime, or if I instead write either of the following slight variations:

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

... or ...

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;
}

... the expected result, 1234, is printed. Additionally, clang++ 3.7.0 prints the expected 1234 in all cases.

Have I hit a g++ bug or am I missing something here?

like image 974
dudenice Avatar asked Sep 25 '15 13:09

dudenice


People also ask

Are Constexpr functions evaluated at compile time?

A constexpr function that is eligible to be evaluated at compile-time will only be evaluated at compile-time if the return value is used where a constant expression is required. Otherwise, compile-time evaluation is not guaranteed.

What is the point of Constexpr?

constexpr indicates that the value, or return value, is constant and, where possible, is computed at compile time. A constexpr integral value can be used wherever a const integer is required, such as in template arguments and array declarations.

Is Constexpr function static?

A constexpr specifier used in an object declaration or non-static member function (until C++14) implies const . A constexpr specifier used in a function or static data member (since C++17) declaration implies inline .


1 Answers

This looks related to the gcc bug [5 regression] Constant expression factory function initializes std::array with static storage duration strangely and if we try this with gcc head live example it works fine.

The bug report has the following similar example, where the static variable case exhibits a similar issue while the automatic variable case does not:

#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
}
like image 187
Shafik Yaghmour Avatar answered Jan 01 '23 23:01

Shafik Yaghmour