I ran into a compiler error that only reproduces on gcc, I narrowed it down to a minimal reproducible sample that also fails on msvc but still compiles fine with clang. Here's the code:
struct vec
{
float _x[2];
constexpr float operator[](int index) const { return _x[index]; }
float& operator[](int index) { return _x[index]; }
};
struct mat
{
vec _x[2];
constexpr vec operator[](int index) const { return _x[index]; }
vec& operator[](int index) { return _x[index]; }
};
constexpr float bar(float f)
{
return f;
}
constexpr float one(mat const& m)
{
return m[0][0]; // fails in gcc 5+, msvc
}
constexpr float two(mat const& m)
{
return bar(m[0][0]); // fails in gcc 5+
}
From what I can tell, overload resolution for vec::operator[] on line 24 does not consider the const overload (line 5) because mat::operator[] const (line 13) returns by value, not by const reference, but I'm not sure why that prevents consideration of vec::operator[] const. Error message from gcc:
: In function 'constexpr float one(const mat&)':
:24:18: error: call to non-constexpr function 'float& vec::operator[](int)'
return m[0][0]; // fails in gcc 5+, msvc
And from msvc:
(22): error C3615: constexpr function 'one' cannot result in a constant expression
(24): note: failure was caused by call of undefined function or one not declared 'constexpr'
(24): note: see usage of 'vec::operator []'
The original code compiles fine in msvc but the sample does not so it took me a little bit to find what was allowing it work with msvc. Apprently, passing the return value through another constexpr function somehow forces msvc to consider the const overload but I have no idea what the reason for this is. Is this a bug or the result of some esoteric language rules? Which compiler is correct?
Last question here is that this is only a problem because the const overloads return by value, if they return by const reference there are no errors on any compiler. Is returning by value here a useless pessimization that I should remove?