Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Explicit defaulted default constructor and aggregates

How to explain the difference, when I compile #if 0 and #if 1 versions of the following code:

#include <cstdlib>

struct A
{ 
    explicit A() = default; // explicitly defaulted or deleted constructors are allowed for aggregates (since C++11)
#if 1
private :
#endif
    int i;
};

int
main()
{
    A a = {};
    return EXIT_SUCCESS;
}
  • for #if 0 all is fine, compilation successful.
  • for #if 1 compilation failed with error message:

    error: chosen constructor is explicit in copy-initialization

What is the difference for expression A a = {}; depending on whether A is aggreagate or not?

like image 875
Tomilov Anatoliy Avatar asked Nov 04 '15 13:11

Tomilov Anatoliy


People also ask

Can we call a default constructor explicitly?

Note that if a constructor has any arguments that do not have default values, it is not a default constructor. The following example defines a class with one constructor and two default constructors. You can declare default constructors as explicitly defaulted functions or deleted functions.

What is the difference between default constructor provided compiler and a user define default constructor?

If you don't define a constructor for a class, a default parameterless constructor is automatically created by the compiler. Default constructor is created only if there are no constructors. If you define any constructor for your class, no default constructor is automatically created.

What are various types of default constructors?

Default Constructors in C++ The two main types of constructors are default constructors and parameterized constructors. Default constructors do not take any parameters. If a default constructor is not provided by the programmer explicitly, then the compiler provides a implicit default constructor.


1 Answers

TL;DR: Clang and GCC are wrong in rejecting your code. CWG 1630´s resolution made default-initialization well-formed regardless of the chosen default constructor being explicit or not.


In the variation of your code in which i is private, A is not an aggregate, as these cannot have private members. As long as i is public, however, A is an aggregate1, and no constructor is invoked since aggregate initialization is performed (see blue box), so your constructor being explicit is irrelevant.

enter image description here

However, as soon as you introduce the private member, you necessitate value-initialization as per the red box. Hence [dcl.init]/(8.2) applies:

enter image description here

[dcl.init]/(7.1) defines default-initialization for this case:

enter image description here

And §13.3.1.3 gives

For […] default-initialization, the candidate functions are all the constructors of the class of the object being initialized.

At no point is the original context - copy- or direct-initialization - considered. (§13.3.1.7 doesn't apply either.) In fact, this is intended; see CWG #1518:

This issue is resolved by the resolution of issue 1630: default initialization now uses 13.3.1.3 [over.match.ctor], which now permits explicit constructors for default-initialization.

Clang and GCC (and VC++) haven't implemented the corresponding DR yet and are thus incorrect in rejecting the code in C++14 mode.


1) Your class has a user-declared constructor, but it isn't user-provided, i.e. not impeding your class from being an aggregate. Recall the definition in [dcl.init.aggr]/1:

An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).

like image 160
Columbo Avatar answered Oct 13 '22 13:10

Columbo