https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88165

--- Comment #12 from JC Liang <jcl at nvidia dot com> ---
(In reply to Jonathan Wakely from comment #10)
> (In reply to Fedor Chelnokov from comment #7)
> > This struct definition:
> > ```
> > struct A {
> >     struct B {
> >         int i = 0;
> >         B() {}
> 
> This declares default constructor, meaning that the type is default
> constructible. Period.
> 
> By declaring B(); you assert that B is default constructible.
> 
> >     };
> >     A(B = {});
> 
> This is valid, because the user-provided default constructor for B is all
> the compiler needs to see to know that B={} is valid.
> 
> > };
> > ```
> > is accepted by GCC, but another one ({} replaced with = default) is not:
> > ```
> > struct C {
> >     struct D {
> >         int i = 0;
> >         D() = default;
> 
> This declares a default constructor that might be defined implicitly by the
> compiler, **or** it might get deleted if the member definitions of D would
> make the implicit default constructor ill-formed. This is obviously very
> different from the case where you declare B(); There is no assertion that D
> is default constructible, the compiler has to deduce whether or not that's
> true. That depends on the default member initializer for D::i. The
> initializer (which is just '0' here) is a "complete class context" which
> means it is not processed until the class D is complete (this allows you to
> use other members, or e.g. sizeof(D) as the initializer).
> 
> A nested class like C::D is not complete until its enclosing class is
> complete. This means the initializer for C::D::i is compiled after C is
> complete. This means whether C::D is default constructible is not known
> until C is complete.
> 
> 
> >     };
> >     C(D = {});
> 
> This requires checking whether C::D is default constructible, but we are
> still in the body of C, so C is not complete, which means C::D is not
> complete, which means we don't know if C::D is default constructible.
> 
> > };
> > ```
> > Demo: https://gcc.godbolt.org/z/WTPdTn1Yf
> > 
> > Could you please explain why? I though that both must be same accepted or
> > same rejected.
> 
> I hope the explanation above helps.
> 
> GCC trunk now has a tweak to parse simple initializers like 0 immediately,
> instead of waiting for the class to be complete (because 0 doesn't depend on
> anything in the class). But for the original example in comment 0 the
> initializer std::numeric_limits<double>::max(); has to perform name lookup
> and overload resolution, and so is still delayed until the class is complete.

This is an excellent explanation, hope it benefits everyone who got here from
Google search.

Reply via email to