Error when using in-class initialization of non-static data member and nested class constructor

后端 未结 2 1450
半阙折子戏
半阙折子戏 2020-12-07 15:46

The following code is quite trivial and I expected that it should compile fine.

struct A
{
    struct B
    {
        int i = 0;
    };

    B b;

    A(cons         


        
2条回答
  •  广开言路
    2020-12-07 15:48

    Is this code really incorrect or are the compilers wrong?

    Well, neither. The standard has a defect -- it says both that A is considered complete while parsing the initializer for B::i, and that B::B() (which uses the initializer for B::i) can be used within the definition of A. That's clearly cyclic. Consider this:

    struct A {
      struct B {
        int i = (A(), 0);
      };
      A() noexcept(!noexcept(B()));
    };
    

    This has a contradiction: B::B() is implicitly noexcept iff A() does not throw, and A() does not throw iff B::B() is not noexcept. There are a number of other cycles and contradictions in this area.

    This is tracked by core issues 1360 and 1397. Note in particular this note in core issue 1397:

    Perhaps the best way of addressing this would be to make it ill-formed for a non-static data member initializer to use a defaulted constructor of its class.

    That's a special case of the rule that I implemented in Clang to resolve this issue. Clang's rule is that a defaulted default constructor for a class cannot be used before the non-static data member initializers for that class are parsed. Hence Clang issues a diagnostic here:

        A(const B& _b = B())
                        ^
    

    ... because Clang parses default arguments before it parses default initializers, and this default argument would require B's default initializers to have already been parsed (in order to implicitly define B::B()).

提交回复
热议问题