I have the following sample class Foo with nested class Bar and everything is constexpr:
class Foo
{
private:
template <typename T>
struct Bar
{
constexpr Bar(){}
constexpr int DoTheThing() const
{
return 1;
}
};
public:
constexpr static auto b = Bar<int>{};
constexpr Foo() {}
constexpr int DoTheThing() const
{
return b.DoTheThing();
}
};
And I want to test that calling Foo::DoTheThing returns 1:
int main()
{
constexpr Foo f;
static_assert(f.DoTheThing() == 1, "DoTheThing() should return 1");
}
GCC and Clang both complain here, but MSVC does not
GCC says:
error:
constexpr Foo::Bar<T>::Bar() [with T = int]used before its definitionconstexpr static auto b = Bar<int>{};
And Clang:
error: constexpr variable
bmust be initialized by a constant expressionconstexpr static auto b = Bar<int>{};
I cannot tell if the standard disallows this, but my guess is that somehow b is an incomplete type.
What makes things more interesting is that I can get GCC and Clang to behave if I remove the constexpr, or if I move the definition of Bar outside of Foo.
Which of these compilers is correct?
Note that this question was inspired by the following:
- Simple constexpr LookUpTable in C++14 (my problem is one part of this unanswered question's problem)
- Nested struct breaks constexpr despite being identical to global ones (this seems to provide some insight into what's going on)
Baroutside ofFooworks suggests to me that a factor here is the the fact that the definition ofFoois not complete until the class is completely declared. Until the end ofFoo's definition, its inner classes are not considered to be fully defined (which is why inline clsas methods can refer to class members that are declared after them).Baris already a literal type, so there is no need for you to define a default constructor (in this example). Clang and GCC compile fine if you take out Bar's constructor. I know that doesn't answer your question, but I thought it was worth mentioning.constexpr staticfromballows everything to work just fine.