Error when using in-class initialization of non-static data member and nested class constructor
Solution 1:
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()
).