Carucel
Carucel

Reputation: 481

Constexpr and templates: compiler bug?

The following works as expected:

#include <array>
constexpr std::array<int, 3> values = {1, 2, 3};
template <int i> struct A { static constexpr int val = values[i]; };
int main() { A<1> a; }

However, I get a compiler error from the MSVC compiler if we use values.size() as template parameter:

int main() { A<values.size()> a; }

The error is expression did not evaluate to a constant. The GCC compiles without error.

Upvotes: 0

Views: 187

Answers (2)

Guillaume Racicot
Guillaume Racicot

Reputation: 41750

MSVC is right. There cannot be undefined behaviour in any constexpr context. Or else this is not a constant expression.

The line:

int main() { A<values.size()> a; }

Is basically:

constexpr auto i = values[values.size()];

Which is out of bound. In fact, MSVC correctly diagnose the error:

example.cpp
<source>(3): error C2131: expression did not evaluate to a constant
C:/msvc/v19_16/include\array(187): note: failure was caused by out of range index 3; allowed range is 0 <= index < 3
<source>(4): note: see reference to class template instantiation 'A<3>' being compiled 
<source>(2): note: see reference to class template instantiation 'std::array<int,3>' being compiled
Compiler returned: 2

On the other hand, both GCC and MSVC accept this code:

int main() { A<values.size() - 1> a; }

Upvotes: 8

NathanOliver
NathanOliver

Reputation: 180415

This is actually a bug/flaw of GCC, not MSVC.

A<values.size()> a;

causes you to access values out of range since the valid indexes are [0, size()). MSVC gives you an error that it can't do that because it is undefined behavior, and that isn't allowed in a constant expression.

Note that clang also diagnoses this correctly and issues an error: https://godbolt.org/z/vmi86S

Upvotes: 3

Related Questions