3

I'm trying to declare a static constexpr member, the type of which is an inner class. This inner class as a constexpr constructor so in my opinion, everything should be fine. But it isn't. In fact, when I move the inner class out of the containing class, everything works fine.

This is a minimal example:

class Foo {
public:
    constexpr Foo(int param) : i(param) {};
    int i;
};

class Bar {
public:
    class InnerFoo {
    public:
        constexpr InnerFoo(int param) : i(param) {};
        int i;
    };

    static constexpr Foo f { 1 };
    static constexpr InnerFoo inner_f { 2 };
}; 

int main() {
    Bar b;
}

The error messages of clang / gcc are not very helpful. Clang tells me:

16 : <source>:16:31: error: constexpr variable 'inner_f' must be initialized by a constant expression
    static constexpr InnerFoo inner_f { 2 };
                              ^~~~~~~~~~~~~
16 : <source>:16:31: note: undefined constructor 'InnerFoo' cannot be used in a constant expression
11 : <source>:11:19: note: declared here
        constexpr InnerFoo(int param) : i(param) {};

I fail to see how the constructor is undefined? It's literally the same thing as for Foo(), and for Foo() it seems to be defined? The error message by gcc is slightly more helpful:

16 : <source>:16:43: error: 'constexpr Bar::InnerFoo::InnerFoo(int)' called in a constant expression before its definition is complete
     static constexpr InnerFoo inner_f { 2 };

But how is the definition not yet 'complete'? Is the definition of a inner class's methods only 'complete' after the containing class has been completely declared? If so, is there any way of re-shuffeling the code so that I can have a static constexpr member of an inner class?

Thanks,

Lukas

Lukas Barth
  • 2,734
  • 18
  • 43
  • 1
    The question may not be an exact match of the dup I linked, but the answer is the same regardless. The class is incomplete. – AndyG Aug 23 '17 at 14:16
  • @AndyG, It's understandable that `Bar` is not complete at that line but why is the nested class not considered complete? – R Sahu Aug 23 '17 at 14:21
  • @RSahu: I believe it has more to do with the fact that a nested class has access to the containing class. As such, it cannot be used in a static constexpr context from within the enclosing class. The C++17 standard is a bit more clear about it than C++11 IMO. – AndyG Aug 23 '17 at 14:28
  • So the problem is not actually InnerFoo being incomplete? InnerFoo's closing "}" has passed at that point, thus by the excerpt from the standard that you give in the post you linked it should be considered complete at the point where inner_f should be initialized, right? I agree that there is a class that InnerFoo has access to which is not complete (namely Bar), but the standard does not say that this makes InnerFoo incomplete? – Lukas Barth Aug 23 '17 at 14:36
  • 1
    @LukasBarth: The problem is that `Bar` is not considered complete until the closing brace. Therefore any types that you define within it cannot be used in a `static constexpr` context inside. – AndyG Aug 23 '17 at 14:42

0 Answers0