Consider the following example code:
#include <array>
struct MyClass
{
size_t value = 0;
constexpr static size_t size() noexcept
{
return 3;
}
};
template <size_t N>
void DoIt()
{
MyClass h;
std::array<int, h.size()> arr;
}
int main()
{
DoIt<1>();
}
When I try to compile this with GCC 7.3.0, I get an error about h not being usable in a non-constexpr context:
cexpr.cpp: In function ‘void DoIt()’:
cexpr.cpp:17:26: error: the value of ‘h’ is not usable in a constant expression
std::array<int, h.size()> arr;
^
cexpr.cpp:16:11: note: ‘h’ was not declared ‘constexpr’
MyClass h;
^
cexpr.cpp:17:27: error: the value of ‘h’ is not usable in a constant expression
std::array<int, h.size()> arr;
^
cexpr.cpp:16:11: note: ‘h’ was not declared ‘constexpr’
MyClass h;
^
However, when I try compiling the exact same code in Clang 6.0.0, it compiles without any errors. Additionally, when I modify the code to not be inside the templated DoIt() function, GCC compiles this just fine:
#include <array>
struct MyClass
{
size_t value = 0;
constexpr static size_t size() noexcept
{
return 3;
}
};
int main()
{
MyClass h;
// this compiles just fine in Clang and GCC
std::array<int, h.size()> arr;
}
I already know how to fix the first code so it compiles on GCC using decltype, but I'm curious to know why doesn't the first piece of code compile with GCC? Is this just a bug in GCC, or is there something I don't understand about using constexpr static member functions?
MyClass::size()?constexprmember function calls in aconstexprconstructor are ignored if the object is defined locally.expression still needs to be evaluated as an expression before it gets resolved (like, I could do(MyClass{} + MyClass{}).size()if MyClass had aoperator+(). The fact that thehexpression has no side-effects is something that could get collapsed fairly late during the compilation process, so it's not entirely unreasonable to require it to beconstexpr.constexprobject is a constant expression. You’re not supposed to be able to use such a variable in a constant expression, but the static member function of course doesn’t really use it.