Does it violate the standard for a non-default structure and does not have a user-defined constructor?

You can define struct (a), which does not have user-defined constructors, and (b), for which a default constructor cannot be generated. For example, Foo in the following:

 struct Baz { Baz(int) {} }; struct Foo { int bar; Baz baz; }; 

You can still create Foo instances using aggregate initialization:

 Foo foo = { 0, Baz(0) }; 

My regular compiler (VS2012) will be reluctant to accept this, but it raises 2 warnings:

warning C4510: "Foo": The default constructor cannot be generated.

warning C4610: struct 'Foo' can never be created - user-defined constructor required

Of course, I just proved the wrong warning # 2 - you can still instantiate using aggregate initialization. In the online compilers I tried, I am satisfied enough to accept the above, so I assume that VS2012 is just overly aggressive with this warning. But I would like to be sure - is this code good, or is it technically violating some obscure part of the standard?

+6
source share
2 answers

The standard explicitly allows cases such as Foo in [12.1p4]:

[...] If there is no constructor declared by the user for class X, a constructor without parameters is implicitly declared as default [...] The default default constructor for class X is defined as being deleted if:

[...]

  • any potentially constructed subobject, with the exception of a non-static data element with a symbol-equal-initializer element, is of type M (or an array of this), and either M does not have a default constructor or overload (13.3) with respect to the default constructor, Ms leads to ambiguity or a function that is removed or inaccessible from the default default constructor

[...]

Baz does not have a default constructor, so the underlined part above is applied (emphasis mine).

In such cases, there is no "w90>" or "poorly formed". An implicitly declared default constructor is defined as remote, that is all. You could do the same directly, and it would still be true.

The definition of aggregates is specified in [8.5.1p1]. For C ++ 14, this is:

An aggregate is an array or class (section 9) without any custom constructors (12.1), private or protected non-static data elements (Section 11), there are no base classes (section 10), and there are no virtual functions (10.3).

The part not provided by the user allows the use of = delete for all constructors that can be implicitly declared (which makes them declared by the user, but not provided by the user), and the class will still be a collection that allows you to use aggregate initialization on it.

As for warning C4610, I ran into it myself and reported it . As you can see, this has been fixed in the upcoming version of VC ++.

Perhaps it is worth mentioning that the example that I used in the error report is taken directly from the standard, where it is processed as correctly formed ([12.2p5.4]:

 struct S { int mi; const std::pair<int,int>& mp; }; S a { 1, {2,3} }; 

This is similar to your case, but here the implicitly declared default constructor is defined as remote, since the class has a non-static member of a reference type that does not have an initializer.

Of course, this is just an example, but I think this is an additional sign that in these cases there is nothing wrong.

+2
source

This is not really aggregate initialization, uniform, which is only recently supported by VS. This warning simply updates them incorrectly to reflect that this type can now be unified.

Aggregates may not have user-defined non-default unused constructors, and the rules for aggregate UDTs are that each member must also be an aggregate. Therefore, Baz is not an aggregate and a direct result, and Foo cannot be.

-1
source

Source: https://habr.com/ru/post/982896/


All Articles