Why does aggregate initialization not work anymore since C++20 if a constructor is explicitly defaulted or deleted?How exactly does __attribute__((constructor)) work?why explicitly delete the constructor?Inheriting-Constructors + In-Class-Initialization of non-default constructabe type failsdefault/delete move constructor and assignment with the existence of RVOWhy does a class with a user-declared destructor have an implicitly defaulted constructor?Why C++11 implicitly deletes my default constructor?Why are implicitly and explicitly deleted move constructors treated differently?Unions in C++11: default constructor seems to be deletedDefault move constructor/assignment and deleted copy constructor/assignmentInitialisation of aggregate with default constructor deleted in c++20

In a topological space if there exists a loop that cannot be contracted to a point does there exist a simple loop that cannot be contracted also?

Why aren’t emergency services using callsigns?

(11 of 11: Meta) What is Pyramid Cult's All-Time Favorite?

Infeasibility in mathematical optimization models

Does this Foo machine halt?

Strangeness with gears

What does Apple mean by "This may decrease battery life"?

In reversi, can you overwrite two chips in one move?

Was the 2019 Lion King film made through motion capture?

'sudo apt-get update' get a warning

A stranger from Norway wants to have money delivered to me

Why are Gatwick's runways too close together?

Is it incorrect to write "I rate this book a 3 out of 4 stars?"

Best gun to modify into a monsterhunter weapon?

Visa National - No Exit Stamp From France on Return to the UK

Author changing name

Why is しない used instead of じゃない?

Does a code snippet compile? Or does it get compiled?

As a 16 year old, how can I keep my money safe from my mother?

Is it really ~648.69 km/s delta-v to "land" on the surface of the Sun?

Accidentals - some in brackets, some not

What are good ways to improve as a writer other than writing courses?

Does two puncture wounds mean venomous snake?

During the Space Shuttle Columbia Disaster of 2003, Why Did The Flight Director Say, "Lock the doors."?



Why does aggregate initialization not work anymore since C++20 if a constructor is explicitly defaulted or deleted?


How exactly does __attribute__((constructor)) work?why explicitly delete the constructor?Inheriting-Constructors + In-Class-Initialization of non-default constructabe type failsdefault/delete move constructor and assignment with the existence of RVOWhy does a class with a user-declared destructor have an implicitly defaulted constructor?Why C++11 implicitly deletes my default constructor?Why are implicitly and explicitly deleted move constructors treated differently?Unions in C++11: default constructor seems to be deletedDefault move constructor/assignment and deleted copy constructor/assignmentInitialisation of aggregate with default constructor deleted in c++20






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








17















I'm migrating a C++ Visual Studio Project from VS2017 to VS2019.



I'm getting an error now, that didn't occur before, that can be reproduced with these few lines of code:



struct Foo

Foo() = default;
int bar;
;
auto test = Foo 0 ;


The error is




(6): error C2440: 'initializing': cannot convert from
'initializer list' to 'Foo'



(6): note: No constructor could take the source type, or
constructor overload resolution was ambiguous




The project is compiled with /std:c++latest flag. I reproduced it on godbolt. If I switch it to /std:c++17, it compiles fine as before.



I tried to compile the same code with clang with -std=c++2a and got a similar error. Also, defaulting or deleting other constructors generates this error.



Apparently, some new C++20 features were added in VS2019 and I'm assuming the origin of this issue is described in https://en.cppreference.com/w/cpp/language/aggregate_initialization.
There it says that an aggregate can be a struct that (among other criteria) has



  • no user-provided, inherited, or explicit constructors (explicitly defaulted or deleted constructors are allowed) (since C++17) (until C++20)

  • no user-declared or inherited constructors (since C++20)

Note that the part in parentheses "explicitly defaulted or deleted constructors are allowed" was dropped and that "user-provided" changed to "user-declared".



So my first question is, am I right assuming that this change in the standard is the reason why my code compiled before but does not anymore?



Of course, it's easy to fix this: Just remove the explicitly defaulted constructors.



However, I have explicitly defaulted and deleted very many constructors in all of my projects because I found it was a good habit to make code much more expressive this way because it simply results in fewer surprises than with implicitly defaulted or deleted constructors. With this change however, this doesn't seem like such a good habit anymore...



So my actual question is:
What is the reasoning behind this change from C++17 to C++20? Was this break of backwards compatibility made on purpose? Was there some trade off like "Ok, we're breaking backwards compatibility here, but it's for the greater good."? What is this greater good?










share|improve this question





















  • 2





    This is the paper. I don't find the rationale (which IMO boils down to "OMG these contrived examples are so surprising they must be fixed") persuasive. YMMV.

    – T.C.
    Jul 30 at 12:20











  • I'd still consider it a good habit, I'd rather consider aggregate initialisation a bad habit...

    – Aconcagua
    Jul 30 at 12:24






  • 1





    To answer the less-important first question, explicitly defaulted constructors are considered to be user-declared, but not user-provided. Thus, the change in wording there is indeed the reason for the new errors. (As a note, the standard falters a little in regards to the term "user-declared", by not properly defining it. It's roughly used as a counterpart to "implicitly-declared", though, which (when combined with the term itself) is enough to, ahem, implicitly define it.)

    – Justin Time
    Jul 30 at 22:13


















17















I'm migrating a C++ Visual Studio Project from VS2017 to VS2019.



I'm getting an error now, that didn't occur before, that can be reproduced with these few lines of code:



struct Foo

Foo() = default;
int bar;
;
auto test = Foo 0 ;


The error is




(6): error C2440: 'initializing': cannot convert from
'initializer list' to 'Foo'



(6): note: No constructor could take the source type, or
constructor overload resolution was ambiguous




The project is compiled with /std:c++latest flag. I reproduced it on godbolt. If I switch it to /std:c++17, it compiles fine as before.



I tried to compile the same code with clang with -std=c++2a and got a similar error. Also, defaulting or deleting other constructors generates this error.



Apparently, some new C++20 features were added in VS2019 and I'm assuming the origin of this issue is described in https://en.cppreference.com/w/cpp/language/aggregate_initialization.
There it says that an aggregate can be a struct that (among other criteria) has



  • no user-provided, inherited, or explicit constructors (explicitly defaulted or deleted constructors are allowed) (since C++17) (until C++20)

  • no user-declared or inherited constructors (since C++20)

Note that the part in parentheses "explicitly defaulted or deleted constructors are allowed" was dropped and that "user-provided" changed to "user-declared".



So my first question is, am I right assuming that this change in the standard is the reason why my code compiled before but does not anymore?



Of course, it's easy to fix this: Just remove the explicitly defaulted constructors.



However, I have explicitly defaulted and deleted very many constructors in all of my projects because I found it was a good habit to make code much more expressive this way because it simply results in fewer surprises than with implicitly defaulted or deleted constructors. With this change however, this doesn't seem like such a good habit anymore...



So my actual question is:
What is the reasoning behind this change from C++17 to C++20? Was this break of backwards compatibility made on purpose? Was there some trade off like "Ok, we're breaking backwards compatibility here, but it's for the greater good."? What is this greater good?










share|improve this question





















  • 2





    This is the paper. I don't find the rationale (which IMO boils down to "OMG these contrived examples are so surprising they must be fixed") persuasive. YMMV.

    – T.C.
    Jul 30 at 12:20











  • I'd still consider it a good habit, I'd rather consider aggregate initialisation a bad habit...

    – Aconcagua
    Jul 30 at 12:24






  • 1





    To answer the less-important first question, explicitly defaulted constructors are considered to be user-declared, but not user-provided. Thus, the change in wording there is indeed the reason for the new errors. (As a note, the standard falters a little in regards to the term "user-declared", by not properly defining it. It's roughly used as a counterpart to "implicitly-declared", though, which (when combined with the term itself) is enough to, ahem, implicitly define it.)

    – Justin Time
    Jul 30 at 22:13














17












17








17


1






I'm migrating a C++ Visual Studio Project from VS2017 to VS2019.



I'm getting an error now, that didn't occur before, that can be reproduced with these few lines of code:



struct Foo

Foo() = default;
int bar;
;
auto test = Foo 0 ;


The error is




(6): error C2440: 'initializing': cannot convert from
'initializer list' to 'Foo'



(6): note: No constructor could take the source type, or
constructor overload resolution was ambiguous




The project is compiled with /std:c++latest flag. I reproduced it on godbolt. If I switch it to /std:c++17, it compiles fine as before.



I tried to compile the same code with clang with -std=c++2a and got a similar error. Also, defaulting or deleting other constructors generates this error.



Apparently, some new C++20 features were added in VS2019 and I'm assuming the origin of this issue is described in https://en.cppreference.com/w/cpp/language/aggregate_initialization.
There it says that an aggregate can be a struct that (among other criteria) has



  • no user-provided, inherited, or explicit constructors (explicitly defaulted or deleted constructors are allowed) (since C++17) (until C++20)

  • no user-declared or inherited constructors (since C++20)

Note that the part in parentheses "explicitly defaulted or deleted constructors are allowed" was dropped and that "user-provided" changed to "user-declared".



So my first question is, am I right assuming that this change in the standard is the reason why my code compiled before but does not anymore?



Of course, it's easy to fix this: Just remove the explicitly defaulted constructors.



However, I have explicitly defaulted and deleted very many constructors in all of my projects because I found it was a good habit to make code much more expressive this way because it simply results in fewer surprises than with implicitly defaulted or deleted constructors. With this change however, this doesn't seem like such a good habit anymore...



So my actual question is:
What is the reasoning behind this change from C++17 to C++20? Was this break of backwards compatibility made on purpose? Was there some trade off like "Ok, we're breaking backwards compatibility here, but it's for the greater good."? What is this greater good?










share|improve this question
















I'm migrating a C++ Visual Studio Project from VS2017 to VS2019.



I'm getting an error now, that didn't occur before, that can be reproduced with these few lines of code:



struct Foo

Foo() = default;
int bar;
;
auto test = Foo 0 ;


The error is




(6): error C2440: 'initializing': cannot convert from
'initializer list' to 'Foo'



(6): note: No constructor could take the source type, or
constructor overload resolution was ambiguous




The project is compiled with /std:c++latest flag. I reproduced it on godbolt. If I switch it to /std:c++17, it compiles fine as before.



I tried to compile the same code with clang with -std=c++2a and got a similar error. Also, defaulting or deleting other constructors generates this error.



Apparently, some new C++20 features were added in VS2019 and I'm assuming the origin of this issue is described in https://en.cppreference.com/w/cpp/language/aggregate_initialization.
There it says that an aggregate can be a struct that (among other criteria) has



  • no user-provided, inherited, or explicit constructors (explicitly defaulted or deleted constructors are allowed) (since C++17) (until C++20)

  • no user-declared or inherited constructors (since C++20)

Note that the part in parentheses "explicitly defaulted or deleted constructors are allowed" was dropped and that "user-provided" changed to "user-declared".



So my first question is, am I right assuming that this change in the standard is the reason why my code compiled before but does not anymore?



Of course, it's easy to fix this: Just remove the explicitly defaulted constructors.



However, I have explicitly defaulted and deleted very many constructors in all of my projects because I found it was a good habit to make code much more expressive this way because it simply results in fewer surprises than with implicitly defaulted or deleted constructors. With this change however, this doesn't seem like such a good habit anymore...



So my actual question is:
What is the reasoning behind this change from C++17 to C++20? Was this break of backwards compatibility made on purpose? Was there some trade off like "Ok, we're breaking backwards compatibility here, but it's for the greater good."? What is this greater good?







c++ c++17 backwards-compatibility c++20






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jul 31 at 7:34







sebrockm

















asked Jul 30 at 12:12









sebrockmsebrockm

2,6611 gold badge4 silver badges23 bronze badges




2,6611 gold badge4 silver badges23 bronze badges










  • 2





    This is the paper. I don't find the rationale (which IMO boils down to "OMG these contrived examples are so surprising they must be fixed") persuasive. YMMV.

    – T.C.
    Jul 30 at 12:20











  • I'd still consider it a good habit, I'd rather consider aggregate initialisation a bad habit...

    – Aconcagua
    Jul 30 at 12:24






  • 1





    To answer the less-important first question, explicitly defaulted constructors are considered to be user-declared, but not user-provided. Thus, the change in wording there is indeed the reason for the new errors. (As a note, the standard falters a little in regards to the term "user-declared", by not properly defining it. It's roughly used as a counterpart to "implicitly-declared", though, which (when combined with the term itself) is enough to, ahem, implicitly define it.)

    – Justin Time
    Jul 30 at 22:13













  • 2





    This is the paper. I don't find the rationale (which IMO boils down to "OMG these contrived examples are so surprising they must be fixed") persuasive. YMMV.

    – T.C.
    Jul 30 at 12:20











  • I'd still consider it a good habit, I'd rather consider aggregate initialisation a bad habit...

    – Aconcagua
    Jul 30 at 12:24






  • 1





    To answer the less-important first question, explicitly defaulted constructors are considered to be user-declared, but not user-provided. Thus, the change in wording there is indeed the reason for the new errors. (As a note, the standard falters a little in regards to the term "user-declared", by not properly defining it. It's roughly used as a counterpart to "implicitly-declared", though, which (when combined with the term itself) is enough to, ahem, implicitly define it.)

    – Justin Time
    Jul 30 at 22:13








2




2





This is the paper. I don't find the rationale (which IMO boils down to "OMG these contrived examples are so surprising they must be fixed") persuasive. YMMV.

– T.C.
Jul 30 at 12:20





This is the paper. I don't find the rationale (which IMO boils down to "OMG these contrived examples are so surprising they must be fixed") persuasive. YMMV.

– T.C.
Jul 30 at 12:20













I'd still consider it a good habit, I'd rather consider aggregate initialisation a bad habit...

– Aconcagua
Jul 30 at 12:24





I'd still consider it a good habit, I'd rather consider aggregate initialisation a bad habit...

– Aconcagua
Jul 30 at 12:24




1




1





To answer the less-important first question, explicitly defaulted constructors are considered to be user-declared, but not user-provided. Thus, the change in wording there is indeed the reason for the new errors. (As a note, the standard falters a little in regards to the term "user-declared", by not properly defining it. It's roughly used as a counterpart to "implicitly-declared", though, which (when combined with the term itself) is enough to, ahem, implicitly define it.)

– Justin Time
Jul 30 at 22:13






To answer the less-important first question, explicitly defaulted constructors are considered to be user-declared, but not user-provided. Thus, the change in wording there is indeed the reason for the new errors. (As a note, the standard falters a little in regards to the term "user-declared", by not properly defining it. It's roughly used as a counterpart to "implicitly-declared", though, which (when combined with the term itself) is enough to, ahem, implicitly define it.)

– Justin Time
Jul 30 at 22:13













3 Answers
3






active

oldest

votes


















17














The abstract from P1008, the proposal that led to the change:




C++ currently allows some types with user-declared constructors to be initialized via aggregate initialization, bypassing those constructors. The result is code that is surprising, confusing, and buggy. This paper proposes a fix that makes initialization semantics in C++ safer, more uniform,and easier to teach. We also discuss the breaking changes that this fix introduces.




One of the examples they give is the following.




struct X 
int i4;
X() = default;
;

int main()
X x1(3); // ill-formed - no matching c’tor
X x23; // compiles!




To me, it's quite clear that the proposed changes are worth the backwards-incompatibility they bear. And indeed, it doesn't seem to be good practice anymore to = default aggregate default constructors.






share|improve this answer






















  • 1





    Shouldn't it be X x23 instead – or comma instead of semicolon after first variable? Apart from, I do consider it good practice to default the constructors, I rather consider aggregate initialisation bad practice (which we now can prevent this way).

    – Aconcagua
    Jul 30 at 12:27












  • @Aconcagua Thanks for the hint. Copy-pasting from a pdf there...

    – lubgr
    Jul 30 at 12:28






  • 3





    Well, they did just make X x1(3); well-formed for aggregates...

    – T.C.
    Jul 30 at 13:48











  • @Aconcagua, why do you think that aggregate initialisation is bad practice?

    – Patrick Fromberg
    Aug 7 at 19:54











  • @PatrickFromberg For aggregate initialisation, you rely on member order as we do not have designated initialisers (yet, at least) as we have in C. Imagine you need to add a new member, and for alignment or other reasons you need to place it in between some others. That will break aggregate initialisation. Constructors can be fixed appropriately, in contrast, so they are just safer.

    – Aconcagua
    2 days ago



















12














The reasoning from P1008 (PDF) can be best understood from two directions:



  1. If you sat a relatively new C++ programmer down in front of a class definition and ask "is this an aggregate", would they be correct?

The common conception of an aggregate is "a class with no constructors". If Typename() = default; is in a class definition, most people will see that as having a constructor. It will behave like the standard default constructor, but the type still has one. That is the broad conception of the idea from many users.



An aggregate is supposed to be a class of pure data, able to have any member assume any value it is given. From that perspective, you have no business giving it constructors of any kind, even if you defaulted them. Which brings us to the next reasoning:



  1. If my class fulfills the requirements of an aggregate, but I don't want it to be an aggregate, how do I do that?

The most obvious answer would be to = default the default constructor, because I'm probably someone from group #1. Obviously, that doesn't work.



Pre-C++20, your options are to give the class some other constructor or to implement one of the special member functions. Neither of these options are palatable, because (by definition) it's not something you actually need to implement; you're just doing it to make some side effect happen.



Post-C++20, the obvious answer works.



By changing the rules in such a way, it makes the difference between an aggregate and non-aggregate visible. Aggregates have no constructors; so if you want a type to be an aggregate, you don't give it constructors.



Oh, and here's a fun fact: pre-C++20, this is an aggregate:



class Agg

Agg() = default;
;


Note that the defaulted constructor is private, so only people with private access to Agg can call it... unless they use Agg, bypasses the constructor and is perfectly legal.



The clear intent of this class is to create a class which can be copied around, but can only get its initial construction from those with private access. This allows forwarding of access controls, as only code which was given an Agg can call functions that take Agg as a parameter. And only code with access to Agg can create one.



Or at least, that's how it is supposed to be.



Now you could fix this more targetedly by saying that it's an aggregate if the defaulted/deleted constructors are not publicly declared. But that feels even more in-congruent; sometimes, a class with a visibly declared constructor is an aggregate and sometimes it isn't, depending on where that visibly declared constructor is.






share|improve this answer

























  • I see... ok, some convincing arguments here, thanks. Your last example would be even better, if you changed = default to = delete as this even more expresses the intent (and Agg still worked in C++17, uff... was not aware of that).

    – sebrockm
    Jul 30 at 13:12












  • @sebrockm: Not really. If you delete the default constructor, then nobody is supposed to be able to create an object of that type (outside of copying). If you make it a private, defaulted constructor, then only people with private access should be able to create one (again, outside of copying).

    – Nicol Bolas
    Jul 30 at 13:13












  • right, slightly different intent. Still, "nobody is supposed to create it (but still everyone can)" is an even more convincing argument than "only some chosen ones are supposed to create it (but still everyone can)". That was my point :)

    – sebrockm
    Jul 30 at 13:16







  • 1





    @sebrockm: But that's easily countered by the argument, "If nobody is supposed to be able to create the object... why does the type exist at all?" And while you can point to various metaprogramming tools which use types purely as engines of computation, none of them actively forbid creating instances of such types, nor are they conceptually broken if someone does so. So why is it important to be able to create a type that cannot be instantiated, rather than just a type where instantiation isn't useful?

    – Nicol Bolas
    Jul 30 at 13:22











  • I think we are talking about different things here. I'm not proposing the deletion of the default c'tor and thus expressing "this shall never be created" is a reasonable thing to do. Still, if I did that, I'd expect that absolutely never there will be an instance of this class. But contrary, everybody can create it. To me, that behavior is even a little more counter intuitive than your example where you do expect objects get created (just who can do it, is a surprise, but not that it can be done at all).

    – sebrockm
    Jul 30 at 13:48


















2














Actually, MSDN addressed your concern in the below document:



Modified specification of aggregate type




In Visual Studio 2019, under /std:c++latest, a class with any user-declared constructor (for example, including a constructor declared = default or = delete) isn't an aggregate. Previously, only user-provided constructors would disqualify a class from being an aggregate. This change puts additional restrictions on how such types can be initialized.







share|improve this answer



























    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f57271400%2fwhy-does-aggregate-initialization-not-work-anymore-since-c20-if-a-constructor%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    17














    The abstract from P1008, the proposal that led to the change:




    C++ currently allows some types with user-declared constructors to be initialized via aggregate initialization, bypassing those constructors. The result is code that is surprising, confusing, and buggy. This paper proposes a fix that makes initialization semantics in C++ safer, more uniform,and easier to teach. We also discuss the breaking changes that this fix introduces.




    One of the examples they give is the following.




    struct X 
    int i4;
    X() = default;
    ;

    int main()
    X x1(3); // ill-formed - no matching c’tor
    X x23; // compiles!




    To me, it's quite clear that the proposed changes are worth the backwards-incompatibility they bear. And indeed, it doesn't seem to be good practice anymore to = default aggregate default constructors.






    share|improve this answer






















    • 1





      Shouldn't it be X x23 instead – or comma instead of semicolon after first variable? Apart from, I do consider it good practice to default the constructors, I rather consider aggregate initialisation bad practice (which we now can prevent this way).

      – Aconcagua
      Jul 30 at 12:27












    • @Aconcagua Thanks for the hint. Copy-pasting from a pdf there...

      – lubgr
      Jul 30 at 12:28






    • 3





      Well, they did just make X x1(3); well-formed for aggregates...

      – T.C.
      Jul 30 at 13:48











    • @Aconcagua, why do you think that aggregate initialisation is bad practice?

      – Patrick Fromberg
      Aug 7 at 19:54











    • @PatrickFromberg For aggregate initialisation, you rely on member order as we do not have designated initialisers (yet, at least) as we have in C. Imagine you need to add a new member, and for alignment or other reasons you need to place it in between some others. That will break aggregate initialisation. Constructors can be fixed appropriately, in contrast, so they are just safer.

      – Aconcagua
      2 days ago
















    17














    The abstract from P1008, the proposal that led to the change:




    C++ currently allows some types with user-declared constructors to be initialized via aggregate initialization, bypassing those constructors. The result is code that is surprising, confusing, and buggy. This paper proposes a fix that makes initialization semantics in C++ safer, more uniform,and easier to teach. We also discuss the breaking changes that this fix introduces.




    One of the examples they give is the following.




    struct X 
    int i4;
    X() = default;
    ;

    int main()
    X x1(3); // ill-formed - no matching c’tor
    X x23; // compiles!




    To me, it's quite clear that the proposed changes are worth the backwards-incompatibility they bear. And indeed, it doesn't seem to be good practice anymore to = default aggregate default constructors.






    share|improve this answer






















    • 1





      Shouldn't it be X x23 instead – or comma instead of semicolon after first variable? Apart from, I do consider it good practice to default the constructors, I rather consider aggregate initialisation bad practice (which we now can prevent this way).

      – Aconcagua
      Jul 30 at 12:27












    • @Aconcagua Thanks for the hint. Copy-pasting from a pdf there...

      – lubgr
      Jul 30 at 12:28






    • 3





      Well, they did just make X x1(3); well-formed for aggregates...

      – T.C.
      Jul 30 at 13:48











    • @Aconcagua, why do you think that aggregate initialisation is bad practice?

      – Patrick Fromberg
      Aug 7 at 19:54











    • @PatrickFromberg For aggregate initialisation, you rely on member order as we do not have designated initialisers (yet, at least) as we have in C. Imagine you need to add a new member, and for alignment or other reasons you need to place it in between some others. That will break aggregate initialisation. Constructors can be fixed appropriately, in contrast, so they are just safer.

      – Aconcagua
      2 days ago














    17












    17








    17







    The abstract from P1008, the proposal that led to the change:




    C++ currently allows some types with user-declared constructors to be initialized via aggregate initialization, bypassing those constructors. The result is code that is surprising, confusing, and buggy. This paper proposes a fix that makes initialization semantics in C++ safer, more uniform,and easier to teach. We also discuss the breaking changes that this fix introduces.




    One of the examples they give is the following.




    struct X 
    int i4;
    X() = default;
    ;

    int main()
    X x1(3); // ill-formed - no matching c’tor
    X x23; // compiles!




    To me, it's quite clear that the proposed changes are worth the backwards-incompatibility they bear. And indeed, it doesn't seem to be good practice anymore to = default aggregate default constructors.






    share|improve this answer















    The abstract from P1008, the proposal that led to the change:




    C++ currently allows some types with user-declared constructors to be initialized via aggregate initialization, bypassing those constructors. The result is code that is surprising, confusing, and buggy. This paper proposes a fix that makes initialization semantics in C++ safer, more uniform,and easier to teach. We also discuss the breaking changes that this fix introduces.




    One of the examples they give is the following.




    struct X 
    int i4;
    X() = default;
    ;

    int main()
    X x1(3); // ill-formed - no matching c’tor
    X x23; // compiles!




    To me, it's quite clear that the proposed changes are worth the backwards-incompatibility they bear. And indeed, it doesn't seem to be good practice anymore to = default aggregate default constructors.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Jul 30 at 12:28

























    answered Jul 30 at 12:24









    lubgrlubgr

    24.3k3 gold badges32 silver badges77 bronze badges




    24.3k3 gold badges32 silver badges77 bronze badges










    • 1





      Shouldn't it be X x23 instead – or comma instead of semicolon after first variable? Apart from, I do consider it good practice to default the constructors, I rather consider aggregate initialisation bad practice (which we now can prevent this way).

      – Aconcagua
      Jul 30 at 12:27












    • @Aconcagua Thanks for the hint. Copy-pasting from a pdf there...

      – lubgr
      Jul 30 at 12:28






    • 3





      Well, they did just make X x1(3); well-formed for aggregates...

      – T.C.
      Jul 30 at 13:48











    • @Aconcagua, why do you think that aggregate initialisation is bad practice?

      – Patrick Fromberg
      Aug 7 at 19:54











    • @PatrickFromberg For aggregate initialisation, you rely on member order as we do not have designated initialisers (yet, at least) as we have in C. Imagine you need to add a new member, and for alignment or other reasons you need to place it in between some others. That will break aggregate initialisation. Constructors can be fixed appropriately, in contrast, so they are just safer.

      – Aconcagua
      2 days ago













    • 1





      Shouldn't it be X x23 instead – or comma instead of semicolon after first variable? Apart from, I do consider it good practice to default the constructors, I rather consider aggregate initialisation bad practice (which we now can prevent this way).

      – Aconcagua
      Jul 30 at 12:27












    • @Aconcagua Thanks for the hint. Copy-pasting from a pdf there...

      – lubgr
      Jul 30 at 12:28






    • 3





      Well, they did just make X x1(3); well-formed for aggregates...

      – T.C.
      Jul 30 at 13:48











    • @Aconcagua, why do you think that aggregate initialisation is bad practice?

      – Patrick Fromberg
      Aug 7 at 19:54











    • @PatrickFromberg For aggregate initialisation, you rely on member order as we do not have designated initialisers (yet, at least) as we have in C. Imagine you need to add a new member, and for alignment or other reasons you need to place it in between some others. That will break aggregate initialisation. Constructors can be fixed appropriately, in contrast, so they are just safer.

      – Aconcagua
      2 days ago








    1




    1





    Shouldn't it be X x23 instead – or comma instead of semicolon after first variable? Apart from, I do consider it good practice to default the constructors, I rather consider aggregate initialisation bad practice (which we now can prevent this way).

    – Aconcagua
    Jul 30 at 12:27






    Shouldn't it be X x23 instead – or comma instead of semicolon after first variable? Apart from, I do consider it good practice to default the constructors, I rather consider aggregate initialisation bad practice (which we now can prevent this way).

    – Aconcagua
    Jul 30 at 12:27














    @Aconcagua Thanks for the hint. Copy-pasting from a pdf there...

    – lubgr
    Jul 30 at 12:28





    @Aconcagua Thanks for the hint. Copy-pasting from a pdf there...

    – lubgr
    Jul 30 at 12:28




    3




    3





    Well, they did just make X x1(3); well-formed for aggregates...

    – T.C.
    Jul 30 at 13:48





    Well, they did just make X x1(3); well-formed for aggregates...

    – T.C.
    Jul 30 at 13:48













    @Aconcagua, why do you think that aggregate initialisation is bad practice?

    – Patrick Fromberg
    Aug 7 at 19:54





    @Aconcagua, why do you think that aggregate initialisation is bad practice?

    – Patrick Fromberg
    Aug 7 at 19:54













    @PatrickFromberg For aggregate initialisation, you rely on member order as we do not have designated initialisers (yet, at least) as we have in C. Imagine you need to add a new member, and for alignment or other reasons you need to place it in between some others. That will break aggregate initialisation. Constructors can be fixed appropriately, in contrast, so they are just safer.

    – Aconcagua
    2 days ago






    @PatrickFromberg For aggregate initialisation, you rely on member order as we do not have designated initialisers (yet, at least) as we have in C. Imagine you need to add a new member, and for alignment or other reasons you need to place it in between some others. That will break aggregate initialisation. Constructors can be fixed appropriately, in contrast, so they are just safer.

    – Aconcagua
    2 days ago














    12














    The reasoning from P1008 (PDF) can be best understood from two directions:



    1. If you sat a relatively new C++ programmer down in front of a class definition and ask "is this an aggregate", would they be correct?

    The common conception of an aggregate is "a class with no constructors". If Typename() = default; is in a class definition, most people will see that as having a constructor. It will behave like the standard default constructor, but the type still has one. That is the broad conception of the idea from many users.



    An aggregate is supposed to be a class of pure data, able to have any member assume any value it is given. From that perspective, you have no business giving it constructors of any kind, even if you defaulted them. Which brings us to the next reasoning:



    1. If my class fulfills the requirements of an aggregate, but I don't want it to be an aggregate, how do I do that?

    The most obvious answer would be to = default the default constructor, because I'm probably someone from group #1. Obviously, that doesn't work.



    Pre-C++20, your options are to give the class some other constructor or to implement one of the special member functions. Neither of these options are palatable, because (by definition) it's not something you actually need to implement; you're just doing it to make some side effect happen.



    Post-C++20, the obvious answer works.



    By changing the rules in such a way, it makes the difference between an aggregate and non-aggregate visible. Aggregates have no constructors; so if you want a type to be an aggregate, you don't give it constructors.



    Oh, and here's a fun fact: pre-C++20, this is an aggregate:



    class Agg

    Agg() = default;
    ;


    Note that the defaulted constructor is private, so only people with private access to Agg can call it... unless they use Agg, bypasses the constructor and is perfectly legal.



    The clear intent of this class is to create a class which can be copied around, but can only get its initial construction from those with private access. This allows forwarding of access controls, as only code which was given an Agg can call functions that take Agg as a parameter. And only code with access to Agg can create one.



    Or at least, that's how it is supposed to be.



    Now you could fix this more targetedly by saying that it's an aggregate if the defaulted/deleted constructors are not publicly declared. But that feels even more in-congruent; sometimes, a class with a visibly declared constructor is an aggregate and sometimes it isn't, depending on where that visibly declared constructor is.






    share|improve this answer

























    • I see... ok, some convincing arguments here, thanks. Your last example would be even better, if you changed = default to = delete as this even more expresses the intent (and Agg still worked in C++17, uff... was not aware of that).

      – sebrockm
      Jul 30 at 13:12












    • @sebrockm: Not really. If you delete the default constructor, then nobody is supposed to be able to create an object of that type (outside of copying). If you make it a private, defaulted constructor, then only people with private access should be able to create one (again, outside of copying).

      – Nicol Bolas
      Jul 30 at 13:13












    • right, slightly different intent. Still, "nobody is supposed to create it (but still everyone can)" is an even more convincing argument than "only some chosen ones are supposed to create it (but still everyone can)". That was my point :)

      – sebrockm
      Jul 30 at 13:16







    • 1





      @sebrockm: But that's easily countered by the argument, "If nobody is supposed to be able to create the object... why does the type exist at all?" And while you can point to various metaprogramming tools which use types purely as engines of computation, none of them actively forbid creating instances of such types, nor are they conceptually broken if someone does so. So why is it important to be able to create a type that cannot be instantiated, rather than just a type where instantiation isn't useful?

      – Nicol Bolas
      Jul 30 at 13:22











    • I think we are talking about different things here. I'm not proposing the deletion of the default c'tor and thus expressing "this shall never be created" is a reasonable thing to do. Still, if I did that, I'd expect that absolutely never there will be an instance of this class. But contrary, everybody can create it. To me, that behavior is even a little more counter intuitive than your example where you do expect objects get created (just who can do it, is a surprise, but not that it can be done at all).

      – sebrockm
      Jul 30 at 13:48















    12














    The reasoning from P1008 (PDF) can be best understood from two directions:



    1. If you sat a relatively new C++ programmer down in front of a class definition and ask "is this an aggregate", would they be correct?

    The common conception of an aggregate is "a class with no constructors". If Typename() = default; is in a class definition, most people will see that as having a constructor. It will behave like the standard default constructor, but the type still has one. That is the broad conception of the idea from many users.



    An aggregate is supposed to be a class of pure data, able to have any member assume any value it is given. From that perspective, you have no business giving it constructors of any kind, even if you defaulted them. Which brings us to the next reasoning:



    1. If my class fulfills the requirements of an aggregate, but I don't want it to be an aggregate, how do I do that?

    The most obvious answer would be to = default the default constructor, because I'm probably someone from group #1. Obviously, that doesn't work.



    Pre-C++20, your options are to give the class some other constructor or to implement one of the special member functions. Neither of these options are palatable, because (by definition) it's not something you actually need to implement; you're just doing it to make some side effect happen.



    Post-C++20, the obvious answer works.



    By changing the rules in such a way, it makes the difference between an aggregate and non-aggregate visible. Aggregates have no constructors; so if you want a type to be an aggregate, you don't give it constructors.



    Oh, and here's a fun fact: pre-C++20, this is an aggregate:



    class Agg

    Agg() = default;
    ;


    Note that the defaulted constructor is private, so only people with private access to Agg can call it... unless they use Agg, bypasses the constructor and is perfectly legal.



    The clear intent of this class is to create a class which can be copied around, but can only get its initial construction from those with private access. This allows forwarding of access controls, as only code which was given an Agg can call functions that take Agg as a parameter. And only code with access to Agg can create one.



    Or at least, that's how it is supposed to be.



    Now you could fix this more targetedly by saying that it's an aggregate if the defaulted/deleted constructors are not publicly declared. But that feels even more in-congruent; sometimes, a class with a visibly declared constructor is an aggregate and sometimes it isn't, depending on where that visibly declared constructor is.






    share|improve this answer

























    • I see... ok, some convincing arguments here, thanks. Your last example would be even better, if you changed = default to = delete as this even more expresses the intent (and Agg still worked in C++17, uff... was not aware of that).

      – sebrockm
      Jul 30 at 13:12












    • @sebrockm: Not really. If you delete the default constructor, then nobody is supposed to be able to create an object of that type (outside of copying). If you make it a private, defaulted constructor, then only people with private access should be able to create one (again, outside of copying).

      – Nicol Bolas
      Jul 30 at 13:13












    • right, slightly different intent. Still, "nobody is supposed to create it (but still everyone can)" is an even more convincing argument than "only some chosen ones are supposed to create it (but still everyone can)". That was my point :)

      – sebrockm
      Jul 30 at 13:16







    • 1





      @sebrockm: But that's easily countered by the argument, "If nobody is supposed to be able to create the object... why does the type exist at all?" And while you can point to various metaprogramming tools which use types purely as engines of computation, none of them actively forbid creating instances of such types, nor are they conceptually broken if someone does so. So why is it important to be able to create a type that cannot be instantiated, rather than just a type where instantiation isn't useful?

      – Nicol Bolas
      Jul 30 at 13:22











    • I think we are talking about different things here. I'm not proposing the deletion of the default c'tor and thus expressing "this shall never be created" is a reasonable thing to do. Still, if I did that, I'd expect that absolutely never there will be an instance of this class. But contrary, everybody can create it. To me, that behavior is even a little more counter intuitive than your example where you do expect objects get created (just who can do it, is a surprise, but not that it can be done at all).

      – sebrockm
      Jul 30 at 13:48













    12












    12








    12







    The reasoning from P1008 (PDF) can be best understood from two directions:



    1. If you sat a relatively new C++ programmer down in front of a class definition and ask "is this an aggregate", would they be correct?

    The common conception of an aggregate is "a class with no constructors". If Typename() = default; is in a class definition, most people will see that as having a constructor. It will behave like the standard default constructor, but the type still has one. That is the broad conception of the idea from many users.



    An aggregate is supposed to be a class of pure data, able to have any member assume any value it is given. From that perspective, you have no business giving it constructors of any kind, even if you defaulted them. Which brings us to the next reasoning:



    1. If my class fulfills the requirements of an aggregate, but I don't want it to be an aggregate, how do I do that?

    The most obvious answer would be to = default the default constructor, because I'm probably someone from group #1. Obviously, that doesn't work.



    Pre-C++20, your options are to give the class some other constructor or to implement one of the special member functions. Neither of these options are palatable, because (by definition) it's not something you actually need to implement; you're just doing it to make some side effect happen.



    Post-C++20, the obvious answer works.



    By changing the rules in such a way, it makes the difference between an aggregate and non-aggregate visible. Aggregates have no constructors; so if you want a type to be an aggregate, you don't give it constructors.



    Oh, and here's a fun fact: pre-C++20, this is an aggregate:



    class Agg

    Agg() = default;
    ;


    Note that the defaulted constructor is private, so only people with private access to Agg can call it... unless they use Agg, bypasses the constructor and is perfectly legal.



    The clear intent of this class is to create a class which can be copied around, but can only get its initial construction from those with private access. This allows forwarding of access controls, as only code which was given an Agg can call functions that take Agg as a parameter. And only code with access to Agg can create one.



    Or at least, that's how it is supposed to be.



    Now you could fix this more targetedly by saying that it's an aggregate if the defaulted/deleted constructors are not publicly declared. But that feels even more in-congruent; sometimes, a class with a visibly declared constructor is an aggregate and sometimes it isn't, depending on where that visibly declared constructor is.






    share|improve this answer













    The reasoning from P1008 (PDF) can be best understood from two directions:



    1. If you sat a relatively new C++ programmer down in front of a class definition and ask "is this an aggregate", would they be correct?

    The common conception of an aggregate is "a class with no constructors". If Typename() = default; is in a class definition, most people will see that as having a constructor. It will behave like the standard default constructor, but the type still has one. That is the broad conception of the idea from many users.



    An aggregate is supposed to be a class of pure data, able to have any member assume any value it is given. From that perspective, you have no business giving it constructors of any kind, even if you defaulted them. Which brings us to the next reasoning:



    1. If my class fulfills the requirements of an aggregate, but I don't want it to be an aggregate, how do I do that?

    The most obvious answer would be to = default the default constructor, because I'm probably someone from group #1. Obviously, that doesn't work.



    Pre-C++20, your options are to give the class some other constructor or to implement one of the special member functions. Neither of these options are palatable, because (by definition) it's not something you actually need to implement; you're just doing it to make some side effect happen.



    Post-C++20, the obvious answer works.



    By changing the rules in such a way, it makes the difference between an aggregate and non-aggregate visible. Aggregates have no constructors; so if you want a type to be an aggregate, you don't give it constructors.



    Oh, and here's a fun fact: pre-C++20, this is an aggregate:



    class Agg

    Agg() = default;
    ;


    Note that the defaulted constructor is private, so only people with private access to Agg can call it... unless they use Agg, bypasses the constructor and is perfectly legal.



    The clear intent of this class is to create a class which can be copied around, but can only get its initial construction from those with private access. This allows forwarding of access controls, as only code which was given an Agg can call functions that take Agg as a parameter. And only code with access to Agg can create one.



    Or at least, that's how it is supposed to be.



    Now you could fix this more targetedly by saying that it's an aggregate if the defaulted/deleted constructors are not publicly declared. But that feels even more in-congruent; sometimes, a class with a visibly declared constructor is an aggregate and sometimes it isn't, depending on where that visibly declared constructor is.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Jul 30 at 13:00









    Nicol BolasNicol Bolas

    304k37 gold badges509 silver badges689 bronze badges




    304k37 gold badges509 silver badges689 bronze badges















    • I see... ok, some convincing arguments here, thanks. Your last example would be even better, if you changed = default to = delete as this even more expresses the intent (and Agg still worked in C++17, uff... was not aware of that).

      – sebrockm
      Jul 30 at 13:12












    • @sebrockm: Not really. If you delete the default constructor, then nobody is supposed to be able to create an object of that type (outside of copying). If you make it a private, defaulted constructor, then only people with private access should be able to create one (again, outside of copying).

      – Nicol Bolas
      Jul 30 at 13:13












    • right, slightly different intent. Still, "nobody is supposed to create it (but still everyone can)" is an even more convincing argument than "only some chosen ones are supposed to create it (but still everyone can)". That was my point :)

      – sebrockm
      Jul 30 at 13:16







    • 1





      @sebrockm: But that's easily countered by the argument, "If nobody is supposed to be able to create the object... why does the type exist at all?" And while you can point to various metaprogramming tools which use types purely as engines of computation, none of them actively forbid creating instances of such types, nor are they conceptually broken if someone does so. So why is it important to be able to create a type that cannot be instantiated, rather than just a type where instantiation isn't useful?

      – Nicol Bolas
      Jul 30 at 13:22











    • I think we are talking about different things here. I'm not proposing the deletion of the default c'tor and thus expressing "this shall never be created" is a reasonable thing to do. Still, if I did that, I'd expect that absolutely never there will be an instance of this class. But contrary, everybody can create it. To me, that behavior is even a little more counter intuitive than your example where you do expect objects get created (just who can do it, is a surprise, but not that it can be done at all).

      – sebrockm
      Jul 30 at 13:48

















    • I see... ok, some convincing arguments here, thanks. Your last example would be even better, if you changed = default to = delete as this even more expresses the intent (and Agg still worked in C++17, uff... was not aware of that).

      – sebrockm
      Jul 30 at 13:12












    • @sebrockm: Not really. If you delete the default constructor, then nobody is supposed to be able to create an object of that type (outside of copying). If you make it a private, defaulted constructor, then only people with private access should be able to create one (again, outside of copying).

      – Nicol Bolas
      Jul 30 at 13:13












    • right, slightly different intent. Still, "nobody is supposed to create it (but still everyone can)" is an even more convincing argument than "only some chosen ones are supposed to create it (but still everyone can)". That was my point :)

      – sebrockm
      Jul 30 at 13:16







    • 1





      @sebrockm: But that's easily countered by the argument, "If nobody is supposed to be able to create the object... why does the type exist at all?" And while you can point to various metaprogramming tools which use types purely as engines of computation, none of them actively forbid creating instances of such types, nor are they conceptually broken if someone does so. So why is it important to be able to create a type that cannot be instantiated, rather than just a type where instantiation isn't useful?

      – Nicol Bolas
      Jul 30 at 13:22











    • I think we are talking about different things here. I'm not proposing the deletion of the default c'tor and thus expressing "this shall never be created" is a reasonable thing to do. Still, if I did that, I'd expect that absolutely never there will be an instance of this class. But contrary, everybody can create it. To me, that behavior is even a little more counter intuitive than your example where you do expect objects get created (just who can do it, is a surprise, but not that it can be done at all).

      – sebrockm
      Jul 30 at 13:48
















    I see... ok, some convincing arguments here, thanks. Your last example would be even better, if you changed = default to = delete as this even more expresses the intent (and Agg still worked in C++17, uff... was not aware of that).

    – sebrockm
    Jul 30 at 13:12






    I see... ok, some convincing arguments here, thanks. Your last example would be even better, if you changed = default to = delete as this even more expresses the intent (and Agg still worked in C++17, uff... was not aware of that).

    – sebrockm
    Jul 30 at 13:12














    @sebrockm: Not really. If you delete the default constructor, then nobody is supposed to be able to create an object of that type (outside of copying). If you make it a private, defaulted constructor, then only people with private access should be able to create one (again, outside of copying).

    – Nicol Bolas
    Jul 30 at 13:13






    @sebrockm: Not really. If you delete the default constructor, then nobody is supposed to be able to create an object of that type (outside of copying). If you make it a private, defaulted constructor, then only people with private access should be able to create one (again, outside of copying).

    – Nicol Bolas
    Jul 30 at 13:13














    right, slightly different intent. Still, "nobody is supposed to create it (but still everyone can)" is an even more convincing argument than "only some chosen ones are supposed to create it (but still everyone can)". That was my point :)

    – sebrockm
    Jul 30 at 13:16






    right, slightly different intent. Still, "nobody is supposed to create it (but still everyone can)" is an even more convincing argument than "only some chosen ones are supposed to create it (but still everyone can)". That was my point :)

    – sebrockm
    Jul 30 at 13:16





    1




    1





    @sebrockm: But that's easily countered by the argument, "If nobody is supposed to be able to create the object... why does the type exist at all?" And while you can point to various metaprogramming tools which use types purely as engines of computation, none of them actively forbid creating instances of such types, nor are they conceptually broken if someone does so. So why is it important to be able to create a type that cannot be instantiated, rather than just a type where instantiation isn't useful?

    – Nicol Bolas
    Jul 30 at 13:22





    @sebrockm: But that's easily countered by the argument, "If nobody is supposed to be able to create the object... why does the type exist at all?" And while you can point to various metaprogramming tools which use types purely as engines of computation, none of them actively forbid creating instances of such types, nor are they conceptually broken if someone does so. So why is it important to be able to create a type that cannot be instantiated, rather than just a type where instantiation isn't useful?

    – Nicol Bolas
    Jul 30 at 13:22













    I think we are talking about different things here. I'm not proposing the deletion of the default c'tor and thus expressing "this shall never be created" is a reasonable thing to do. Still, if I did that, I'd expect that absolutely never there will be an instance of this class. But contrary, everybody can create it. To me, that behavior is even a little more counter intuitive than your example where you do expect objects get created (just who can do it, is a surprise, but not that it can be done at all).

    – sebrockm
    Jul 30 at 13:48





    I think we are talking about different things here. I'm not proposing the deletion of the default c'tor and thus expressing "this shall never be created" is a reasonable thing to do. Still, if I did that, I'd expect that absolutely never there will be an instance of this class. But contrary, everybody can create it. To me, that behavior is even a little more counter intuitive than your example where you do expect objects get created (just who can do it, is a surprise, but not that it can be done at all).

    – sebrockm
    Jul 30 at 13:48











    2














    Actually, MSDN addressed your concern in the below document:



    Modified specification of aggregate type




    In Visual Studio 2019, under /std:c++latest, a class with any user-declared constructor (for example, including a constructor declared = default or = delete) isn't an aggregate. Previously, only user-provided constructors would disqualify a class from being an aggregate. This change puts additional restrictions on how such types can be initialized.







    share|improve this answer





























      2














      Actually, MSDN addressed your concern in the below document:



      Modified specification of aggregate type




      In Visual Studio 2019, under /std:c++latest, a class with any user-declared constructor (for example, including a constructor declared = default or = delete) isn't an aggregate. Previously, only user-provided constructors would disqualify a class from being an aggregate. This change puts additional restrictions on how such types can be initialized.







      share|improve this answer



























        2












        2








        2







        Actually, MSDN addressed your concern in the below document:



        Modified specification of aggregate type




        In Visual Studio 2019, under /std:c++latest, a class with any user-declared constructor (for example, including a constructor declared = default or = delete) isn't an aggregate. Previously, only user-provided constructors would disqualify a class from being an aggregate. This change puts additional restrictions on how such types can be initialized.







        share|improve this answer













        Actually, MSDN addressed your concern in the below document:



        Modified specification of aggregate type




        In Visual Studio 2019, under /std:c++latest, a class with any user-declared constructor (for example, including a constructor declared = default or = delete) isn't an aggregate. Previously, only user-provided constructors would disqualify a class from being an aggregate. This change puts additional restrictions on how such types can be initialized.








        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Jul 30 at 12:24









        santosh dhanawadesantosh dhanawade

        1,21011 silver badges28 bronze badges




        1,21011 silver badges28 bronze badges






























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f57271400%2fwhy-does-aggregate-initialization-not-work-anymore-since-c20-if-a-constructor%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Category:9 (number) SubcategoriesMedia in category "9 (number)"Navigation menuUpload mediaGND ID: 4485639-8Library of Congress authority ID: sh85091979ReasonatorScholiaStatistics

            Circuit construction for execution of conditional statements using least significant bitHow are two different registers being used as “control”?How exactly is the stated composite state of the two registers being produced using the $R_zz$ controlled rotations?Efficiently performing controlled rotations in HHLWould this quantum algorithm implementation work?How to prepare a superposed states of odd integers from $1$ to $sqrtN$?Why is this implementation of the order finding algorithm not working?Circuit construction for Hamiltonian simulationHow can I invert the least significant bit of a certain term of a superposed state?Implementing an oracleImplementing a controlled sum operation

            Magento 2 “No Payment Methods” in Admin New OrderHow to integrate Paypal Express Checkout with the Magento APIMagento 1.5 - Sales > Order > edit order and shipping methods disappearAuto Invoice Check/Money Order Payment methodAdd more simple payment methods?Shipping methods not showingWhat should I do to change payment methods if changing the configuration has no effects?1.9 - No Payment Methods showing upMy Payment Methods not Showing for downloadable/virtual product when checkout?Magento2 API to access internal payment methodHow to call an existing payment methods in the registration form?