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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With