13

I have the following code:

struct Foo
{       
    struct Bar
    {
        std::uint32_t x = -1;

        constexpr Bar(std::uint32_t x) : x(x) {}
    };

    static constexpr Bar CONST_BAR = Bar(0);
};

When I try to compile it I get the following error:

error: ‘constexpr Foo::Bar::Bar(uint32_t)’ called in a constant expression before its definition is complete

Can someone explain to me what is going on? As far as I can see Bar's constructor is defined before the first call.

Live example

Evg
  • 25,259
  • 5
  • 41
  • 83
rozina
  • 4,120
  • 27
  • 49
  • 3
    Related: [`static constexpr` function called in a constant expression is…an error?](https://stackoverflow.com/questions/29551223/static-constexpr-function-called-in-a-constant-expression-is-an-error) and [constexpr struct member initialisation](https://stackoverflow.com/questions/54660899/constexpr-struct-member-initialisation). – Evg Jun 02 '20 at 08:13
  • Quoting from the answer @evg linked to: "class members are generally not considered to be declared until after the class in which they're declared is complete." – einpoklum Jun 02 '20 at 08:20
  • 1
    It's essentially the same issue Evg linked to. [Inside the c'tor of `Bar`, `Foo` is to be considered complete](https://timsong-cpp.github.io/cppwp/n4140/class#mem-2). Meaning it (albeit indirectly) depends on the completeness of `Foo` to be viable in a constant expression. So it cannot be used in contexts where `Foo` is not yet complete. – StoryTeller - Unslander Monica Jun 02 '20 at 08:47
  • That is unfortunate. Thanks for finding the explanation. – rozina Jun 02 '20 at 08:48

2 Answers2

2

I don't have a detailed explanation but I happened to have stumbled upon this problem as well and thought it was at least worth mentioning... Other than placing the definition of CONST_BAR outside of struct Foo, another possible workaround is instantiating Foo:

// Example program
#include <iostream>
#include <string>

template<typename T = void>
struct Foo
{       
    struct Bar
    {
        std::uint32_t x = -1;
    
        constexpr Bar(std::uint32_t x) : x(x) {}
    };
    
    static constexpr Bar CONST_BAR = Bar(0);
};

int main()
{
    std::cout << "x: " << Foo<>::CONST_BAR.x << "\n";
}
303
  • 2,417
  • 1
  • 11
  • 25
0

You might wanna try to initialize like this-

static constexpr Foo::Bar CONST_BAR = Foo::Bar(0);

outside struct Foo because the declaration of struct foo must complete.

JHBonarius
  • 10,824
  • 3
  • 22
  • 41