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?
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.
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.
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 .
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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With