简体   繁体   中英

Designated initializer different behavior before and after c++20

I came across this strange behavior and I can't find a good explanation of it.

The code below will compile successfully before c++20 and only fail if explicit is used.

struct Square {
  int area = 10;

  Square() = default; // only if this is explicit will the compile fail
  Square(const Square& other) = delete;
  Square(Square&& other) = delete;
  Square& operator =(Square&& square) = delete;
  Square& operator =(const Square& square) = delete;
};

int main() {
  Square s = {
      .area = 10
  };
}

Which is strange on its own but turning the compiler to c++20 will make the above code fail with these error messages

gcc

could not convert brace-enclosed initializer list

clang

no matching constructor for initialization of 'Square'


Question :

  • Why does it compile successfully before c++20 unless explicit ? In other words what implicit conversion takes place to make that happen?

  • What changed in c++20 that made this code fail to compile?

Why does it compile successfully before c++20...

The program is ill-formed prior to C++20.

Designited initialisers did not exist in the language prior to C++20. It compiles because of a language extension.

What changed in c++20 that made it not compile anymore?

The program is still ill-formed in C++20.

Designated initialisers are introduced to the language in C++20, and it appears that the rules are slightly different from what the language extension does. The related rules are (from latest draft):

[dcl.init.list] List-initialization of an object or reference of type T is defined as follows:

  • If the braced-init-list contains a designated-initializer-list, T shall be an aggregate class. ...

  • ...

[dcl.init.aggr] An aggregate is an array or a class ([class]) with

  • no user-declared or inherited constructors ([class.ctor]),

  • ...

The behavioural difference of the language extension prior to C++20 may be related to the change in definition of what is an aggregate, as explained by NathanOliver

In C++20, your class is no longer an aggregate. Since it is not an aggregate, you cannot use a designated initializer. This change is the result of P1008 which removed the presence of user provided defaulted or deleted constructors as qualifying for being an aggregate. The example given for why this change needed to be made was:

struct X {
  int i{4};
  X() = default;
};

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

where X x2{3} should not compile but it does because X() = default; doesn't stop it from being an aggregate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM