Closed xmh0511 closed 10 months ago
No.
If a member has a default member initializer and a potentially-evaluated subexpression thereof is an aggregate initialization that would use that default member initializer, the program is ill-formed.
The default member initializer is = B<C>{}
, and the subexpression B<C>{}
is an aggregate initialization, and that subexpression would use the default member initializer because of the default initialization of C b
. The "would use" part doesn't talk about (syntactic) subexpressions anymore.
The "would use" part doesn't talk about (syntactic) subexpressions anymore.
Consider this counter-example:
#include <any>
template<class T>
struct B{T b;};
struct C{
C(){} // introduce a user-declared constructor
std::any v = B<C>{};
};
int main(){
//C c{};
}
In this example, the class C
is not an aggregate due to the user-declared constructor, however, B<C>
is still an aggregate, all implementations just accept this example.
Sure, but that's because the default initialization of C b
doesn't (directly) use the default member initializer; it uses the user-provided default constructor of C. I'm not seeing a problem with the definition of "subexpression" here, as originally claimed.
it uses the user-provided default constructor of C.
[class.base.init] p9 says:
In a non-delegating constructor other than an implicitly-defined copy/move constructor ([class.copy.ctor]), if a given potentially constructed subobject is not designated by a mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no ctor-initializer), then
-[...]
- if the entity is a non-static data member that has a default member initializer ([class.mem]) and either
- [...]
- the constructor's class is not a union, and, if the entity is a member of an anonymous union, no other member of that union is designated by a mem-initializer-id,
the entity is initialized from its default member initializer as specified in [dcl.init];
The used default constructor of C uses the default member initializer, which is subsumed to be used by the aggregate initialization, as you said above: doesn't talk about (syntactic) subexpressions anymore.
Full name of submitter (unless configured in github; will be published with the issue): Jim X
Consider this case:
[dcl.init.aggr] p13 says:
[intro.execution] p4 says:
[intro.execution] p2 says:
B<C>{}
at#1
cause the aggregate initialization ofB<C>
as per [expr.type.conv] p2, which is a default member initializerThat is, the initializer is as if it was
{}
, however, this is an empty initialization list, which has an empty elements, that is, there is no subexpression of{}
. However, the major implementations say the example is ill-formed, which most likely is regulated by [dcl.init.aggr] p13.Moreover, [dcl.init.aggr] p5 says:
That is,
B<C>::b
is copy-initialized from{}
. The whole default member initializer, as per current wording, is at best{{}}
.Suggested Resolution
In this example, we may want to expect
C{}
as the thereof subexpression of the default member initializerB<C>{}
, andC{}
cause the aggregate initialization that would useB<C>{}
.